diff --git a/messages/bg-BG.json b/messages/bg-BG.json index 1bc2272c..5deb59e3 100644 --- a/messages/bg-BG.json +++ b/messages/bg-BG.json @@ -181,7 +181,7 @@ "baseDomain": "Базов домейн", "subdomnainDescription": "Поддомейнът, където ресурсът ще бъде достъпен.", "resourceRawSettings": "TCP/UDP настройки", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Конфигурирайте как ресурсът ще бъде достъпен чрез TCP/UDP", "protocol": "Протокол", "protocolSelect": "Изберете протокол", "resourcePortNumber": "Номер на порт", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Настройките за прокси бяха успешно актуализирани", "proxyErrorUpdate": "Неуспешно актуализиране на настройки на прокси", "proxyErrorUpdateDescription": "Възникна грешка при актуализиране на настройки на прокси", - "targetAddr": "Host", + "targetAddr": "Хост", "targetPort": "Порт", "targetProtocol": "Протокол", "targetTlsSettings": "Конфигурация на защитена връзка", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Актуализации на продукта", "productUpdateEmpty": "Няма актуализации", "dismissAll": "Отхвърляне на всички", - "pangolinUpdateAvailable": "Налична е нова версия", + "pangolinUpdateAvailable": "Актуализация е налична", "pangolinUpdateAvailableInfo": "Версия {version} е готова за инсталиране", - "pangolinUpdateAvailableReleaseNotes": "Преглед на бележките за издание", + "pangolinUpdateAvailableReleaseNotes": "Преглед на бележките за изданието", "newtUpdateAvailable": "Ново обновление", "newtUpdateAvailableInfo": "Нова версия на Newt е налична. Моля, обновете до последната версия за най-добро изживяване.", "domainPickerEnterDomain": "Домейн", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 дни", "logRetention90Days": "90 дни", "logRetentionForever": "Завинаги", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Край на следващата година", "actionLogsDescription": "Прегледайте историята на действията, извършени в тази организация", "accessLogsDescription": "Прегледайте заявките за удостоверяване на достъпа до ресурсите в тази организация", "licenseRequiredToUse": "Необходим е лиценз Enterprise, за да се използва тази функция.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Това ще генерира нови удостоверителни данни и незабавно ще прекъсне връзката на отдалечения възел. Отдалеченият възел ще трябва да се рестартира с новите удостоверителни данни.", "remoteExitNodeRegenerateCredentialsConfirmation": "Сигурни ли сте, че искате да генерирате новите удостоверителни данни за този отдалечен възел?", "remoteExitNodeRegenerateCredentialsWarning": "Това ще генерира нови удостоверителни данни. Отдалеченият възел ще остане свързан, докато не го рестартирате ръчно и използвате новите удостоверителни данни.", - "agent": "Agent" + "agent": "Агент" } diff --git a/messages/cs-CZ.json b/messages/cs-CZ.json index 6436503f..be3d2232 100644 --- a/messages/cs-CZ.json +++ b/messages/cs-CZ.json @@ -181,7 +181,7 @@ "baseDomain": "Základní doména", "subdomnainDescription": "Subdoména, kde bude zdroj přístupný.", "resourceRawSettings": "Nastavení TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Nakonfigurujte, jak bude dokument přístupný přes TCP/UDP", "protocol": "Protokol", "protocolSelect": "Vybrat protokol", "resourcePortNumber": "Číslo portu", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Nastavení proxy bylo úspěšně aktualizováno", "proxyErrorUpdate": "Aktualizace nastavení proxy se nezdařila", "proxyErrorUpdateDescription": "Došlo k chybě při aktualizaci nastavení proxy", - "targetAddr": "Host", + "targetAddr": "Hostitel", "targetPort": "Přístav", "targetProtocol": "Protokol", "targetTlsSettings": "Nastavení bezpečného připojení", @@ -1320,7 +1320,7 @@ "productUpdateTitle": "Aktualizace produktu", "productUpdateEmpty": "Žádné aktualizace", "dismissAll": "Odmítnout vše", - "pangolinUpdateAvailable": "K dispozici je nová verze", + "pangolinUpdateAvailable": "Dostupná aktualizace", "pangolinUpdateAvailableInfo": "Verze {version} je připravena k instalaci", "pangolinUpdateAvailableReleaseNotes": "Zobrazit poznámky k vydání", "newtUpdateAvailable": "Dostupná aktualizace", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 dní", "logRetention90Days": "90 dní", "logRetentionForever": "Navždy", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Konec následujícího roku", "actionLogsDescription": "Zobrazit historii akcí provedených v této organizaci", "accessLogsDescription": "Zobrazit žádosti o ověření přístupu pro zdroje v této organizaci", "licenseRequiredToUse": "Pro použití této funkce je vyžadována licence pro podnikání.", diff --git a/messages/de-DE.json b/messages/de-DE.json index 3eba335f..333c7052 100644 --- a/messages/de-DE.json +++ b/messages/de-DE.json @@ -181,7 +181,7 @@ "baseDomain": "Basis-Domain", "subdomnainDescription": "Die Subdomäne, auf die die Ressource zugegriffen werden soll.", "resourceRawSettings": "TCP/UDP Einstellungen", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Konfigurieren, wie auf die Ressource über TCP/UDP zugegriffen wird", "protocol": "Protokoll", "protocolSelect": "Wählen Sie ein Protokoll", "resourcePortNumber": "Portnummer", @@ -1102,7 +1102,7 @@ "actionDeleteIdpOrg": "IDP-Organisationsrichtlinie löschen", "actionListIdpOrgs": "IDP-Organisationen auflisten", "actionUpdateIdpOrg": "IDP-Organisation aktualisieren", - "actionCreateClient": "Client anlegen", + "actionCreateClient": "Endgerät anlegen", "actionDeleteClient": "Client löschen", "actionUpdateClient": "Client aktualisieren", "actionListClients": "Clients auflisten", @@ -1320,7 +1320,7 @@ "productUpdateTitle": "Produkt-Updates", "productUpdateEmpty": "Keine Updates", "dismissAll": "Alle verwerfen", - "pangolinUpdateAvailable": "Neue Version verfügbar", + "pangolinUpdateAvailable": "Update verfügbar", "pangolinUpdateAvailableInfo": "Version {version} ist bereit zur Installation", "pangolinUpdateAvailableReleaseNotes": "Versionshinweise anzeigen", "newtUpdateAvailable": "Update verfügbar", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 Tage", "logRetention90Days": "90 Tage", "logRetentionForever": "Für immer", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Ende des folgenden Jahres", "actionLogsDescription": "Verlauf der in dieser Organisation durchgeführten Aktionen anzeigen", "accessLogsDescription": "Zugriffsauth-Anfragen für Ressourcen in dieser Organisation anzeigen", "licenseRequiredToUse": "Um diese Funktion nutzen zu können, ist eine Enterprise-Lizenz erforderlich.", diff --git a/messages/es-ES.json b/messages/es-ES.json index 239a83c0..1ff02bca 100644 --- a/messages/es-ES.json +++ b/messages/es-ES.json @@ -181,7 +181,7 @@ "baseDomain": "Dominio base", "subdomnainDescription": "El subdominio al que el recurso será accesible.", "resourceRawSettings": "Configuración TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Configurar cómo se accederá al recurso a través de TCP/UDP", "protocol": "Protocolo", "protocolSelect": "Seleccionar un protocolo", "resourcePortNumber": "Número de puerto", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "La configuración del proxy se ha actualizado correctamente", "proxyErrorUpdate": "Error al actualizar la configuración del proxy", "proxyErrorUpdateDescription": "Se ha producido un error al actualizar la configuración del proxy", - "targetAddr": "Host", + "targetAddr": "Anfitrión", "targetPort": "Puerto", "targetProtocol": "Protocolo", "targetTlsSettings": "Configuración de conexión segura", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Actualizaciones de producto", "productUpdateEmpty": "Sin actualizaciones", "dismissAll": "Descartar todo", - "pangolinUpdateAvailable": "Nueva versión disponible", + "pangolinUpdateAvailable": "Actualización disponible", "pangolinUpdateAvailableInfo": "La versión {version} está lista para instalar", - "pangolinUpdateAvailableReleaseNotes": "Ver notas del lanzamiento", + "pangolinUpdateAvailableReleaseNotes": "Ver notas de lanzamiento", "newtUpdateAvailable": "Nueva actualización disponible", "newtUpdateAvailableInfo": "Hay una nueva versión de Newt disponible. Actualice a la última versión para la mejor experiencia.", "domainPickerEnterDomain": "Dominio", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 días", "logRetention90Days": "90 días", "logRetentionForever": "Para siempre", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Fin del año siguiente", "actionLogsDescription": "Ver un historial de acciones realizadas en esta organización", "accessLogsDescription": "Ver solicitudes de acceso a los recursos de esta organización", "licenseRequiredToUse": "Se requiere una licencia Enterprise para utilizar esta función.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Esto regenerará las credenciales y desconectará inmediatamente el nodo de salida remoto. El nodo de salida remoto tendrá que reiniciarse con las nuevas credenciales.", "remoteExitNodeRegenerateCredentialsConfirmation": "¿Estás seguro de que quieres regenerar las credenciales para este nodo de salida remoto?", "remoteExitNodeRegenerateCredentialsWarning": "Esto regenerará las credenciales. El nodo de salida remoto permanecerá conectado hasta que lo reinicie manualmente y utilice las nuevas credenciales.", - "agent": "Agent" + "agent": "Agente" } diff --git a/messages/fr-FR.json b/messages/fr-FR.json index 6b489450..63e2b5d8 100644 --- a/messages/fr-FR.json +++ b/messages/fr-FR.json @@ -181,7 +181,7 @@ "baseDomain": "Domaine racine", "subdomnainDescription": "Le sous-domaine où la ressource sera accessible.", "resourceRawSettings": "Paramètres TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Configurer comment la ressource sera accédée via TCP/UDP", "protocol": "Protocole", "protocolSelect": "Choisir un protocole", "resourcePortNumber": "Numéro de port", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Les paramètres du proxy ont été mis à jour avec succès", "proxyErrorUpdate": "Échec de la mise à jour des paramètres du proxy", "proxyErrorUpdateDescription": "Une erreur s'est produite lors de la mise à jour des paramètres du proxy", - "targetAddr": "Host", + "targetAddr": "Hôte", "targetPort": "Port", "targetProtocol": "Protocole", "targetTlsSettings": "Configuration sécurisée de connexion", @@ -1322,7 +1322,7 @@ "dismissAll": "Tout cacher", "pangolinUpdateAvailable": "Mise à jour disponible", "pangolinUpdateAvailableInfo": "La version {version} est prête à être installée", - "pangolinUpdateAvailableReleaseNotes": "Voir les notes de version", + "pangolinUpdateAvailableReleaseNotes": "Voir les notes de publication", "newtUpdateAvailable": "Mise à jour disponible", "newtUpdateAvailableInfo": "Une nouvelle version de Newt est disponible. Veuillez mettre à jour vers la dernière version pour une meilleure expérience.", "domainPickerEnterDomain": "Domaine", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 jours", "logRetention90Days": "90 jours", "logRetentionForever": "Pour toujours", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Fin de l'année suivante", "actionLogsDescription": "Voir l'historique des actions effectuées dans cette organisation", "accessLogsDescription": "Voir les demandes d'authentification d'accès aux ressources de cette organisation", "licenseRequiredToUse": "Une licence Entreprise est nécessaire pour utiliser cette fonctionnalité.", diff --git a/messages/it-IT.json b/messages/it-IT.json index 1468acd5..441c9676 100644 --- a/messages/it-IT.json +++ b/messages/it-IT.json @@ -181,7 +181,7 @@ "baseDomain": "Dominio Base", "subdomnainDescription": "Il sottodominio in cui la risorsa sarà accessibile.", "resourceRawSettings": "Impostazioni TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Configura come accedere alla risorsa tramite TCP/UDP", "protocol": "Protocollo", "protocolSelect": "Seleziona un protocollo", "resourcePortNumber": "Numero Porta", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Aggiornamenti Prodotto", "productUpdateEmpty": "Nessun aggiornamento", "dismissAll": "Ignora tutto", - "pangolinUpdateAvailable": "Nuova versione disponibile", + "pangolinUpdateAvailable": "Aggiornamento Disponibile", "pangolinUpdateAvailableInfo": "La versione {version} è pronta per l'installazione", - "pangolinUpdateAvailableReleaseNotes": "Visualizza note di rilascio", + "pangolinUpdateAvailableReleaseNotes": "Visualizza Note Di Rilascio", "newtUpdateAvailable": "Aggiornamento Disponibile", "newtUpdateAvailableInfo": "È disponibile una nuova versione di Newt. Si prega di aggiornare all'ultima versione per la migliore esperienza.", "domainPickerEnterDomain": "Dominio", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 giorni", "logRetention90Days": "90 giorni", "logRetentionForever": "Per Sempre", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Fine dell'anno successivo", "actionLogsDescription": "Visualizza una cronologia delle azioni eseguite in questa organizzazione", "accessLogsDescription": "Visualizza le richieste di autenticazione di accesso per le risorse in questa organizzazione", "licenseRequiredToUse": "Per utilizzare questa funzione è necessaria una licenza Enterprise.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Questo rigenererà le credenziali e disconnetterà immediatamente il nodo di uscita remoto. Il nodo di uscita remoto dovrà essere riavviato con le nuove credenziali.", "remoteExitNodeRegenerateCredentialsConfirmation": "Sei sicuro di voler rigenerare le credenziali per questo nodo di uscita remoto?", "remoteExitNodeRegenerateCredentialsWarning": "Questo rigenererà le credenziali. Il nodo di uscita remoto rimarrà connesso finché non lo riavvierai manualmente e userai le nuove credenziali.", - "agent": "Agent" + "agent": "Agente" } diff --git a/messages/ko-KR.json b/messages/ko-KR.json index a479eb49..82a12e4e 100644 --- a/messages/ko-KR.json +++ b/messages/ko-KR.json @@ -181,7 +181,7 @@ "baseDomain": "기본 도메인", "subdomnainDescription": "리소스에 접근할 수 있는 하위 도메인입니다.", "resourceRawSettings": "TCP/UDP 설정", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "TCP/UDP를 통해 리소스에 접근하는 방법을 구성하세요.", "protocol": "프로토콜", "protocolSelect": "프로토콜 선택", "resourcePortNumber": "포트 번호", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "프록시 설정이 성공적으로 업데이트되었습니다", "proxyErrorUpdate": "프록시 설정 업데이트에 실패했습니다.", "proxyErrorUpdateDescription": "프록시 설정을 업데이트하는 동안 오류가 발생했습니다", - "targetAddr": "Host", + "targetAddr": "호스트", "targetPort": "포트", "targetProtocol": "프로토콜", "targetTlsSettings": "보안 연결 구성", @@ -1320,7 +1320,7 @@ "productUpdateTitle": "제품 업데이트", "productUpdateEmpty": "업데이트 없음", "dismissAll": "모두 해제", - "pangolinUpdateAvailable": "새 버전 사용 가능", + "pangolinUpdateAvailable": "업데이트 가능", "pangolinUpdateAvailableInfo": "버전 {version}을(를) 설치할 준비가 되었습니다", "pangolinUpdateAvailableReleaseNotes": "릴리스 노트 보기", "newtUpdateAvailable": "업데이트 가능", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 일", "logRetention90Days": "90 일", "logRetentionForever": "영구", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "다음 연도 말", "actionLogsDescription": "이 조직에서 수행된 작업의 기록을 봅니다", "accessLogsDescription": "이 조직의 자원에 대한 접근 인증 요청을 확인합니다", "licenseRequiredToUse": "이 기능을 사용하려면 Enterprise 라이선스가 필요합니다.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "이 과정은 자격 증명을 다시 생성하고 원격 종료 노드와의 연결을 즉시 해제합니다. 원격 종료 노드는 새 자격 증명으로 다시 시작되어야 합니다.", "remoteExitNodeRegenerateCredentialsConfirmation": "이 원격 종료 노드에 대한 자격 증명을 다시 생성하시겠습니까?", "remoteExitNodeRegenerateCredentialsWarning": "이 과정은 자격 증명을 다시 생성합니다. 수동으로 다시 시작하고 새 자격 증명을 사용하기 전까지 원격 종료 노드는 연결된 상태로 유지됩니다.", - "agent": "Agent" + "agent": "에이전트" } diff --git a/messages/nb-NO.json b/messages/nb-NO.json index 057949a3..ec7553b6 100644 --- a/messages/nb-NO.json +++ b/messages/nb-NO.json @@ -181,7 +181,7 @@ "baseDomain": "Grunndomene", "subdomnainDescription": "Underdomenet hvor ressursen vil være tilgjengelig.", "resourceRawSettings": "TCP/UDP-innstillinger", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Konfigurer hvordan ressursen vil bli tilgjengelig over TCP/UDP", "protocol": "Protokoll", "protocolSelect": "Velg en protokoll", "resourcePortNumber": "Portnummer", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Proxy innstillinger har blitt oppdatert", "proxyErrorUpdate": "En feil oppsto under oppdatering av proxyinnstillinger", "proxyErrorUpdateDescription": "En feil oppsto under oppdatering av proxyinnstillinger", - "targetAddr": "Host", + "targetAddr": "Vert", "targetPort": "Port", "targetProtocol": "Protokoll", "targetTlsSettings": "Sikker tilkoblings-konfigurasjon", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Oppdateringer om produktet", "productUpdateEmpty": "Ingen oppdateringer", "dismissAll": "Avvis alle", - "pangolinUpdateAvailable": "Ny versjon tilgjengelig", + "pangolinUpdateAvailable": "Oppdatering tilgjengelig", "pangolinUpdateAvailableInfo": "Versjon {version} er klar til å installere", - "pangolinUpdateAvailableReleaseNotes": "Se utgivelsnotater", + "pangolinUpdateAvailableReleaseNotes": "Se utgivelsesnotater", "newtUpdateAvailable": "Oppdatering tilgjengelig", "newtUpdateAvailableInfo": "En ny versjon av Newt er tilgjengelig. Vennligst oppdater til den nyeste versjonen for den beste opplevelsen.", "domainPickerEnterDomain": "Domene", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 dager", "logRetention90Days": "90 dager", "logRetentionForever": "Alltid", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Slutt på neste år", "actionLogsDescription": "Vis historikk for handlinger som er utført i denne organisasjonen", "accessLogsDescription": "Vis autoriseringsforespørsler for ressurser i denne organisasjonen", "licenseRequiredToUse": "En Enterprise lisens er påkrevd for å bruke denne funksjonen.", diff --git a/messages/nl-NL.json b/messages/nl-NL.json index b98d8dc3..c235676a 100644 --- a/messages/nl-NL.json +++ b/messages/nl-NL.json @@ -181,7 +181,7 @@ "baseDomain": "Basis domein", "subdomnainDescription": "Het subdomein waar de bron toegankelijk zal zijn.", "resourceRawSettings": "TCP/UDP instellingen", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Stel in hoe de bron wordt benaderd via TCP/UDP", "protocol": "Protocol", "protocolSelect": "Selecteer een protocol", "resourcePortNumber": "Nummer van poort", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Proxyinstellingen zijn succesvol bijgewerkt", "proxyErrorUpdate": "Bijwerken van proxy-instellingen mislukt", "proxyErrorUpdateDescription": "Fout opgetreden tijdens het bijwerken van de proxy-instellingen", - "targetAddr": "Host", + "targetAddr": "Hostnaam", "targetPort": "Poort", "targetProtocol": "Protocol", "targetTlsSettings": "HTTPS & TLS instellingen", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Update Producten", "productUpdateEmpty": "Geen updates", "dismissAll": "Alles afwijzen", - "pangolinUpdateAvailable": "Nieuwe versie beschikbaar", + "pangolinUpdateAvailable": "Update beschikbaar", "pangolinUpdateAvailableInfo": "Versie {version} is klaar om te installeren", - "pangolinUpdateAvailableReleaseNotes": "Bekijk release notities", + "pangolinUpdateAvailableReleaseNotes": "Uitgaveopmerkingen bekijken", "newtUpdateAvailable": "Update beschikbaar", "newtUpdateAvailableInfo": "Er is een nieuwe versie van Newt beschikbaar. Update naar de nieuwste versie voor de beste ervaring.", "domainPickerEnterDomain": "Domein", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 dagen", "logRetention90Days": "90 dagen", "logRetentionForever": "Voor altijd", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Einde van volgend jaar", "actionLogsDescription": "Bekijk een geschiedenis van acties die worden uitgevoerd in deze organisatie", "accessLogsDescription": "Toegangsverificatieverzoeken voor resources in deze organisatie bekijken", "licenseRequiredToUse": "Een Enterprise-licentie is vereist om deze functie te gebruiken.", diff --git a/messages/pl-PL.json b/messages/pl-PL.json index 8a0ec10b..99817d14 100644 --- a/messages/pl-PL.json +++ b/messages/pl-PL.json @@ -181,7 +181,7 @@ "baseDomain": "Bazowa domena", "subdomnainDescription": "Poddomena, w której zasób będzie dostępny.", "resourceRawSettings": "Ustawienia TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Skonfiguruj jak zasób będzie dostępny przez TCP/UDP", "protocol": "Protokół", "protocolSelect": "Wybierz protokół", "resourcePortNumber": "Numer portu", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Aktualizacje produktu", "productUpdateEmpty": "Brak aktualizacji", "dismissAll": "Zamknij wszystkie", - "pangolinUpdateAvailable": "Dostępna jest nowa wersja", + "pangolinUpdateAvailable": "Dostępna aktualizacja", "pangolinUpdateAvailableInfo": "Wersja {version} jest gotowa do zainstalowania", - "pangolinUpdateAvailableReleaseNotes": "Zobacz notatki o wydaniu", + "pangolinUpdateAvailableReleaseNotes": "Zobacz informacje o wydaniu", "newtUpdateAvailable": "Dostępna aktualizacja", "newtUpdateAvailableInfo": "Nowa wersja Newt jest dostępna. Prosimy o aktualizację do najnowszej wersji dla najlepszej pracy.", "domainPickerEnterDomain": "Domena", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 dni", "logRetention90Days": "90 dni", "logRetentionForever": "Na zawsze", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Koniec następnego roku", "actionLogsDescription": "Zobacz historię działań wykonywanych w tej organizacji", "accessLogsDescription": "Wyświetl prośby o autoryzację dostępu do zasobów w tej organizacji", "licenseRequiredToUse": "Licencja Enterprise jest wymagana do korzystania z tej funkcji.", diff --git a/messages/pt-PT.json b/messages/pt-PT.json index 1421b27c..41ae04b0 100644 --- a/messages/pt-PT.json +++ b/messages/pt-PT.json @@ -181,7 +181,7 @@ "baseDomain": "Domínio Base", "subdomnainDescription": "O subdomínio onde o recurso será acessível.", "resourceRawSettings": "Configurações TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Configurar como o recurso será acessado sobre TCP/UDP", "protocol": "Protocolo", "protocolSelect": "Selecione um protocolo", "resourcePortNumber": "Número da Porta", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Configurações de proxy atualizadas com sucesso", "proxyErrorUpdate": "Falha ao atualizar configurações de proxy", "proxyErrorUpdateDescription": "Ocorreu um erro ao atualizar as configurações de proxy", - "targetAddr": "Host", + "targetAddr": "Servidor", "targetPort": "Porta", "targetProtocol": "Protocolo", "targetTlsSettings": "Configuração de conexão segura", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Atualizações de Produto", "productUpdateEmpty": "Não há atualizações", "dismissAll": "Recusar tudo", - "pangolinUpdateAvailable": "Nova versão disponível", + "pangolinUpdateAvailable": "Atualização disponível", "pangolinUpdateAvailableInfo": "A versão {version} está pronta para ser instalada", - "pangolinUpdateAvailableReleaseNotes": "Ver notas de lançamento", + "pangolinUpdateAvailableReleaseNotes": "Ver notas de versão", "newtUpdateAvailable": "Nova Atualização Disponível", "newtUpdateAvailableInfo": "Uma nova versão do Newt está disponível. Atualize para a versão mais recente para uma melhor experiência.", "domainPickerEnterDomain": "Domínio", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 dias", "logRetention90Days": "90 dias", "logRetentionForever": "Permanentemente", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Fim do ano seguinte", "actionLogsDescription": "Visualizar histórico de ações realizadas nesta organização", "accessLogsDescription": "Ver solicitações de autenticação de recursos nesta organização", "licenseRequiredToUse": "É necessária uma licença empresarial para usar esse recurso.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Isto irá regenerar as credenciais e desconectar imediatamente o nó de saída remota. O nó de saída remota precisará ser reiniciado com as novas credenciais.", "remoteExitNodeRegenerateCredentialsConfirmation": "Você tem certeza que deseja regenerar as credenciais para este nó de saída remota?", "remoteExitNodeRegenerateCredentialsWarning": "Isto irá regenerar as credenciais. O nó de saída remota permanecerá conectado até que você o reinicie manualmente e use as novas credenciais.", - "agent": "Agent" + "agent": "Representante" } diff --git a/messages/ru-RU.json b/messages/ru-RU.json index 53583ceb..d687b783 100644 --- a/messages/ru-RU.json +++ b/messages/ru-RU.json @@ -181,7 +181,7 @@ "baseDomain": "Базовый домен", "subdomnainDescription": "Поддомен, в котором ресурс будет доступен.", "resourceRawSettings": "Настройки TCP/UDP", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Настройка доступа к ресурсу по TCP/UDP", "protocol": "Протокол", "protocolSelect": "Выберите протокол", "resourcePortNumber": "Номер порта", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "Настройки прокси успешно обновлены", "proxyErrorUpdate": "Не удалось обновить настройки прокси", "proxyErrorUpdateDescription": "Произошла ошибка при обновлении настроек прокси", - "targetAddr": "Host", + "targetAddr": "Хост", "targetPort": "Порт", "targetProtocol": "Протокол", "targetTlsSettings": "Конфигурация безопасного соединения", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Обновления продуктов", "productUpdateEmpty": "Нет обновлений", "dismissAll": "Отклонить все", - "pangolinUpdateAvailable": "Доступна новая версия", + "pangolinUpdateAvailable": "Доступно обновление", "pangolinUpdateAvailableInfo": "Версия {version} готова к установке", - "pangolinUpdateAvailableReleaseNotes": "Просмотреть заметки о выпуске", + "pangolinUpdateAvailableReleaseNotes": "Просмотреть примечания к выпуску", "newtUpdateAvailable": "Доступно обновление", "newtUpdateAvailableInfo": "Доступна новая версия Newt. Пожалуйста, обновитесь до последней версии для лучшего опыта.", "domainPickerEnterDomain": "Домен", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 дней", "logRetention90Days": "90 дней", "logRetentionForever": "Всегда", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Конец следующего года", "actionLogsDescription": "Просмотр истории действий, выполненных в этой организации", "accessLogsDescription": "Просмотр запросов авторизации доступа к ресурсам этой организации", "licenseRequiredToUse": "Для использования этой функции требуется лицензия предприятия.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Это позволит восстановить учётные данные и немедленно отключить удаленный узел выхода. Удаленный узел выхода должен быть перезапущен с новыми учетными данными.", "remoteExitNodeRegenerateCredentialsConfirmation": "Вы уверены, что хотите восстановить учетные данные для этого удаленного выхода узла?", "remoteExitNodeRegenerateCredentialsWarning": "Это позволит восстановить учетные данные. Удалённый узел останется подключенным, пока вы не перезапустите его вручную и воспользуетесь новыми учетными данными.", - "agent": "Agent" + "agent": "Агент" } diff --git a/messages/tr-TR.json b/messages/tr-TR.json index b31a1948..7119808a 100644 --- a/messages/tr-TR.json +++ b/messages/tr-TR.json @@ -181,7 +181,7 @@ "baseDomain": "Temel Alan Adı", "subdomnainDescription": "Kaynağınızın erişilebileceği alt alan adı.", "resourceRawSettings": "TCP/UDP Ayarları", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "Kaynaklara TCP/UDP üzerinden nasıl erişileceğini yapılandırın", "protocol": "Protokol", "protocolSelect": "Bir protokol seçin", "resourcePortNumber": "Port Numarası", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "Ürün Güncellemeleri", "productUpdateEmpty": "Güncelleme yok", "dismissAll": "Hepsini Kapat", - "pangolinUpdateAvailable": "Yeni sürüm mevcut", + "pangolinUpdateAvailable": "Güncelleme Mevcut", "pangolinUpdateAvailableInfo": "Sürüm {version} yüklenmeye hazır", - "pangolinUpdateAvailableReleaseNotes": "Sürüm notlarını görüntüleyin", + "pangolinUpdateAvailableReleaseNotes": "Yayın Notlarını Görüntüle", "newtUpdateAvailable": "Güncelleme Mevcut", "newtUpdateAvailableInfo": "Newt'in yeni bir versiyonu mevcut. En iyi deneyim için lütfen en son sürüme güncelleyin.", "domainPickerEnterDomain": "Alan Adı", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 gün", "logRetention90Days": "90 gün", "logRetentionForever": "Sonsuza kadar", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "Bir sonraki yılın sonu", "actionLogsDescription": "Bu organizasyondaki eylemler geçmişini görüntüleyin", "accessLogsDescription": "Bu organizasyondaki kaynaklar için erişim kimlik doğrulama isteklerini görüntüleyin", "licenseRequiredToUse": "Bu özelliği kullanmak için bir kurumsal lisans gereklidir.", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "Bu, kimlik bilgilerini yeniden oluşturacak ve hemen uzak çıkış düğümünün bağlantısını kesecek. Uzak çıkış düğümü, yeni kimlik bilgileri ile yeniden başlatılmalıdır.", "remoteExitNodeRegenerateCredentialsConfirmation": "Bu uzak çıkış düğümü için kimlik bilgilerini yeniden oluşturmak istediğinizden emin misiniz?", "remoteExitNodeRegenerateCredentialsWarning": "Bu, kimlik bilgilerini yeniden oluşturacak. Uzak çıkış düğümü, manuel olarak yeniden başlatılana ve yeni kimlik bilgiler kullanılana kadar bağlı kalacak.", - "agent": "Agent" + "agent": "Aracı" } diff --git a/messages/zh-CN.json b/messages/zh-CN.json index e304c9bf..b8e1f2b1 100644 --- a/messages/zh-CN.json +++ b/messages/zh-CN.json @@ -181,7 +181,7 @@ "baseDomain": "根域名", "subdomnainDescription": "可访问资源的子域。", "resourceRawSettings": "TCP/UDP 设置", - "resourceRawSettingsDescription": "Configure how the resource will be accessed over TCP/UDP", + "resourceRawSettingsDescription": "配置如何通过 TCP/UDP 访问资源", "protocol": "协议", "protocolSelect": "选择协议", "resourcePortNumber": "端口号", @@ -499,7 +499,7 @@ "proxyUpdatedDescription": "已成功更新代理设置", "proxyErrorUpdate": "更新代理设置失败", "proxyErrorUpdateDescription": "更新代理设置时出错", - "targetAddr": "Host", + "targetAddr": "主机", "targetPort": "端口", "targetProtocol": "协议", "targetTlsSettings": "安全连接配置", @@ -1320,9 +1320,9 @@ "productUpdateTitle": "产品更新", "productUpdateEmpty": "无更新", "dismissAll": "关闭所有", - "pangolinUpdateAvailable": "新版本可用", + "pangolinUpdateAvailable": "可用更新", "pangolinUpdateAvailableInfo": "版本 {version} 已准备就绪", - "pangolinUpdateAvailableReleaseNotes": "查看发布笔记", + "pangolinUpdateAvailableReleaseNotes": "查看发布说明", "newtUpdateAvailable": "更新可用", "newtUpdateAvailableInfo": "新版本的 Newt 已可用。请更新到最新版本以获得最佳体验。", "domainPickerEnterDomain": "域名", @@ -2108,7 +2108,7 @@ "logRetention30Days": "30 天", "logRetention90Days": "90 天", "logRetentionForever": "永远的", - "logRetentionEndOfFollowingYear": "End of following year", + "logRetentionEndOfFollowingYear": "下一年结束", "actionLogsDescription": "查看此机构执行的操作历史", "accessLogsDescription": "查看此机构资源的访问认证请求", "licenseRequiredToUse": "需要企业许可证才能使用此功能。", @@ -2270,5 +2270,5 @@ "remoteExitNodeRegenerateAndDisconnectWarning": "这将重新生成凭据并立即断开远程退出节点。远程退出节点将需要用新的凭据重启。", "remoteExitNodeRegenerateCredentialsConfirmation": "您确定要重新生成此远程退出节点的凭据吗?", "remoteExitNodeRegenerateCredentialsWarning": "这将重新生成凭据。远程退出节点将保持连接,直到您手动重启它并使用新凭据。", - "agent": "Agent" + "agent": "代理" } diff --git a/package-lock.json b/package-lock.json index 28f9f163..a903480e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "SEE LICENSE IN LICENSE AND README.md", "dependencies": { "@asteasolutions/zod-to-openapi": "8.2.0", - "@aws-sdk/client-s3": "3.946.0", + "@aws-sdk/client-s3": "3.947.0", "@faker-js/faker": "10.1.0", "@headlessui/react": "2.2.9", "@hookform/resolvers": "5.2.2", @@ -60,7 +60,7 @@ "date-fns": "4.1.0", "drizzle-orm": "0.45.0", "eslint": "9.39.1", - "eslint-config-next": "16.0.7", + "eslint-config-next": "16.0.8", "express": "5.2.1", "express-rate-limit": "8.2.1", "glob": "13.0.0", @@ -131,7 +131,7 @@ "@types/jmespath": "0.15.2", "@types/js-yaml": "4.0.9", "@types/jsonwebtoken": "9.0.10", - "@types/node": "24.10.1", + "@types/node": "24.10.2", "@types/nodemailer": "7.0.4", "@types/nprogress": "0.2.3", "@types/pg": "8.15.6", @@ -152,7 +152,7 @@ "tsc-alias": "1.8.16", "tsx": "4.21.0", "typescript": "5.9.3", - "typescript-eslint": "8.48.1" + "typescript-eslint": "8.49.0" } }, "node_modules/@alloc/quick-lru": { @@ -396,32 +396,32 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.946.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.946.0.tgz", - "integrity": "sha512-Y3ww3yd1wzmS2r3qgH3jg4MxCTdeNrae2J1BmdV+IW/2R2gFWJva5U5GbS6KUSUxanJBRG7gd8uOIi1b0EMOng==", + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.947.0.tgz", + "integrity": "sha512-ICgnI8D3ccIX9alsLksPFY2bX5CAIbyB+q19sXJgPhzCJ5kWeQ6LQ5xBmRVT5kccmsVGbbJdhnLXHyiN5LZsWg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.946.0", - "@aws-sdk/credential-provider-node": "3.946.0", + "@aws-sdk/core": "3.947.0", + "@aws-sdk/credential-provider-node": "3.947.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", - "@aws-sdk/middleware-flexible-checksums": "3.946.0", + "@aws-sdk/middleware-flexible-checksums": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-sdk-s3": "3.946.0", + "@aws-sdk/middleware-sdk-s3": "3.947.0", "@aws-sdk/middleware-ssec": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.946.0", + "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", - "@aws-sdk/signature-v4-multi-region": "3.946.0", + "@aws-sdk/signature-v4-multi-region": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.946.0", + "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", @@ -461,6 +461,388 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.947.0.tgz", + "integrity": "sha512-sDwcO8SP290WSErY1S8pz8hTafeghKmmWjNVks86jDK30wx62CfazOTeU70IpWgrUBEygyXk/zPogHsUMbW2Rg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.947.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.947.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.947.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.7", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.14", + "@smithy/middleware-retry": "^4.4.14", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.13", + "@smithy/util-defaults-mode-node": "^4.2.16", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.947.0.tgz", + "integrity": "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.7", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.947.0.tgz", + "integrity": "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.947.0.tgz", + "integrity": "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.947.0.tgz", + "integrity": "sha512-A2ZUgJUJZERjSzvCi2NR/hBVbVkTXPD0SdKcR/aITb30XwF+n3T963b+pJl90qhOspoy7h0IVYNR7u5Nr9tJdQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/credential-provider-env": "3.947.0", + "@aws-sdk/credential-provider-http": "3.947.0", + "@aws-sdk/credential-provider-login": "3.947.0", + "@aws-sdk/credential-provider-process": "3.947.0", + "@aws-sdk/credential-provider-sso": "3.947.0", + "@aws-sdk/credential-provider-web-identity": "3.947.0", + "@aws-sdk/nested-clients": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.947.0.tgz", + "integrity": "sha512-u7M3hazcB7aJiVwosNdJRbIJDzbwQ861NTtl6S0HmvWpixaVb7iyhJZWg8/plyUznboZGBm7JVEdxtxv3u0bTA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/nested-clients": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.947.0.tgz", + "integrity": "sha512-S0Zqebr71KyrT6J4uYPhwV65g4V5uDPHnd7dt2W34FcyPu+hVC7Hx4MFmsPyVLeT5cMCkkZvmY3kAoEzgUPJJg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.947.0", + "@aws-sdk/credential-provider-http": "3.947.0", + "@aws-sdk/credential-provider-ini": "3.947.0", + "@aws-sdk/credential-provider-process": "3.947.0", + "@aws-sdk/credential-provider-sso": "3.947.0", + "@aws-sdk/credential-provider-web-identity": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.947.0.tgz", + "integrity": "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.947.0.tgz", + "integrity": "sha512-NktnVHTGaUMaozxycYrepvb3yfFquHTQ53lt6hBEVjYBzK3C4tVz0siUpr+5RMGLSiZ5bLBp2UjJPgwx4i4waQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.947.0", + "@aws-sdk/core": "3.947.0", + "@aws-sdk/token-providers": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.947.0.tgz", + "integrity": "sha512-gokm/e/YHiHLrZgLq4j8tNAn8RJDPbIcglFRKgy08q8DmAqHQ8MXAKW3eS0QjAuRXU9mcMmUo1NrX6FRNBCCPw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/nested-clients": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.947.0.tgz", + "integrity": "sha512-DS2tm5YBKhPW2PthrRBDr6eufChbwXe0NjtTZcYDfUCXf0OR+W6cIqyKguwHMJ+IyYdey30AfVw9/Lb5KB8U8A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.18.7", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-stream": "^4.5.6", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.947.0.tgz", + "integrity": "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.7", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/nested-clients": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.947.0.tgz", + "integrity": "sha512-DjRJEYNnHUTu9kGPPQDTSXquwSEd6myKR4ssI4FaYLFhdT3ldWpj73yYt807H3tdmhS7vPmdVqchSJnjurUQAw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.947.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.947.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.947.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.7", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.14", + "@smithy/middleware-retry": "^4.4.14", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.13", + "@smithy/util-defaults-mode-node": "^4.2.16", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.947.0.tgz", + "integrity": "sha512-UaYmzoxf9q3mabIA2hc4T6x5YSFUG2BpNjAZ207EA1bnQMiK+d6vZvb83t7dIWL/U1de1sGV19c1C81Jf14rrA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/token-providers": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.947.0.tgz", + "integrity": "sha512-X/DyB8GuK44rsE89Tn5+s542B3PhGbXQSgV8lvqHDzvicwCt0tWny6790st6CPETrVVV2K3oJMfG5U3/jAmaZA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.947.0", + "@aws-sdk/nested-clients": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.947.0.tgz", + "integrity": "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.947.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "node_modules/@aws-sdk/client-sesv2": { "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sesv2/-/client-sesv2-3.946.0.tgz", @@ -517,6 +899,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.946.0.tgz", "integrity": "sha512-kGAs5iIVyUz4p6TX3pzG5q3cNxXnVpC4pwRC6DCSaSv9ozyPjc2d74FsK4fZ+J+ejtvCdJk72uiuQtWJc86Wuw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -566,6 +949,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.946.0.tgz", "integrity": "sha512-u2BkbLLVbMFrEiXrko2+S6ih5sUZPlbVyRPtXOqMHlCyzr70sE8kIiD6ba223rQeIFPcYfW/wHc6k4ihW2xxVg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.936.0", @@ -590,6 +974,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.946.0.tgz", "integrity": "sha512-P4l+K6wX1tf8LmWUvZofdQ+BgCNyk6Tb9u1H10npvqpuCD+dCM4pXIBq3PQcv/juUBOvLGGREo+Govuh3lfD0Q==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -606,6 +991,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.946.0.tgz", "integrity": "sha512-/zeOJ6E7dGZQ/l2k7KytEoPJX0APIhwt0A79hPf/bUpMF4dDs2P6JmchDrotk0a0Y/MIdNF8sBQ/MEOPnBiYoQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -627,6 +1013,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.946.0.tgz", "integrity": "sha512-Pdgcra3RivWj/TuZmfFaHbqsvvgnSKO0CxlRUMMr0PgBiCnUhyl+zBktdNOeGsOPH2fUzQpYhcUjYUgVSdcSDQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -652,6 +1039,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.946.0.tgz", "integrity": "sha512-5iqLNc15u2Zx+7jOdQkIbP62N7n2031tw5hkmIG0DLnozhnk64osOh2CliiOE9x3c4P9Pf4frAwgyy9GzNTk2g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -671,6 +1059,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.946.0.tgz", "integrity": "sha512-I7URUqnBPng1a5y81OImxrwERysZqMBREG6svhhGeZgxmqcpAZ8z5ywILeQXdEOCuuES8phUp/ojzxFjPXp/eA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "3.946.0", @@ -694,6 +1083,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.946.0.tgz", "integrity": "sha512-GtGHX7OGqIeVQ3DlVm5RRF43Qmf3S1+PLJv9svrdvAhAdy2bUb044FdXXqrtSsIfpzTKlHgQUiRo5MWLd35Ntw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -711,6 +1101,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.946.0.tgz", "integrity": "sha512-LeGSSt2V5iwYey1ENGY75RmoDP3bA2iE/py8QBKW8EDA8hn74XBLkprhrK5iccOvU3UGWY8WrEKFAFGNjJOL9g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sso": "3.946.0", @@ -730,6 +1121,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.946.0.tgz", "integrity": "sha512-ocBCvjWfkbjxElBI1QUxOnHldsNhoU0uOICFvuRDAZAoxvypJHN3m5BJkqb7gqorBbcv3LRgmBdEnWXOAvq+7Q==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -778,15 +1170,15 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.946.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.946.0.tgz", - "integrity": "sha512-HJA7RIWsnxcChyZ1hNF/3JICkYCqDonxoeG8FkrmLRBknZ8WVdJiPD420/UwrWaa5F2MuTDA92jxk77rI09h1w==", + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.947.0.tgz", + "integrity": "sha512-kXXxS2raNESNO+zR0L4YInVjhcGGNI2Mx0AE1ThRhDkAt2se3a+rGf9equ9YvOqA1m8Jl/GSI8cXYvSxXmS9Ag==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.946.0", + "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", @@ -801,6 +1193,30 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/core": { + "version": "3.947.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.947.0.tgz", + "integrity": "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.7", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.10", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.936.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", @@ -864,6 +1280,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.946.0.tgz", "integrity": "sha512-0UTFmFd8PX2k/jLu/DBmR+mmLQWAtUGHYps9Rjx3dcXNwaMLaa/39NoV3qn7Dwzfpqc6JZlZzBk+NDOCJIHW9g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -903,6 +1320,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.946.0.tgz", "integrity": "sha512-7QcljCraeaWQNuqmOoAyZs8KpZcuhPiqdeeKoRd397jVGNRehLFsZbIMOvwaluUDFY11oMyXOkQEERe1Zo2fCw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -921,6 +1339,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.946.0.tgz", "integrity": "sha512-rjAtEguukeW8mlyEQMQI56vxFoyWlaNwowmz1p1rav948SUjtrzjHAp4TOQWhibb7AR7BUTHBCgIcyCRjBEf4g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -986,6 +1405,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.946.0.tgz", "integrity": "sha512-61FZ685lKiJuQ06g6U7K3PL9EwKCxNm51wNlxyKV57nnl1GrLD0NC8O3/hDNkCQLNBArT9y3IXl2H7TtIxP8Jg==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.946.0", @@ -1003,6 +1423,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.946.0.tgz", "integrity": "sha512-a5c+rM6CUPX2ExmUZ3DlbLlS5rQr4tbdoGcgBsjnAHiYx8MuMNAI+8M7wfjF13i2yvUQj5WEIddvLpayfEZj9g==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.946.0", @@ -1086,6 +1507,7 @@ "version": "3.946.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.946.0.tgz", "integrity": "sha512-a2UwwvzbK5AxHKUBupfg4s7VnkqRAHjYsuezHnKCniczmT4HZfP1NnfwwvLKEH8qaTrwenxjKSfq4UWmWkvG+Q==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-user-agent": "3.946.0", @@ -3401,9 +3823,9 @@ "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.7.tgz", - "integrity": "sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA==", + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.8.tgz", + "integrity": "sha512-1miV0qXDcLUaOdHridVPCh4i39ElRIAraseVIbb3BEqyZ5ol9sPyjTP/GNTPV5rBxqxjF6/vv5zQTVbhiNaLqA==", "license": "MIT", "dependencies": { "fast-glob": "3.3.1" @@ -7066,6 +7488,39 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/@react-email/preview-server/node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-email/preview-server/node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/@react-email/preview-server/node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@react-email/render": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-email/render/-/render-2.0.0.tgz", @@ -9088,9 +9543,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "24.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz", + "integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9263,17 +9718,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", - "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz", + "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/type-utils": "8.48.1", - "@typescript-eslint/utils": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "graphemer": "^1.4.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/type-utils": "8.49.0", + "@typescript-eslint/utils": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" @@ -9286,7 +9740,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.48.1", + "@typescript-eslint/parser": "^8.49.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -9301,15 +9755,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", - "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz", + "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4" }, "engines": { @@ -9325,13 +9779,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", - "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.49.0.tgz", + "integrity": "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.1", - "@typescript-eslint/types": "^8.48.1", + "@typescript-eslint/tsconfig-utils": "^8.49.0", + "@typescript-eslint/types": "^8.49.0", "debug": "^4.3.4" }, "engines": { @@ -9346,13 +9800,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", - "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz", + "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1" + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9363,9 +9817,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", - "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.49.0.tgz", + "integrity": "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9379,14 +9833,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", - "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz", + "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -9403,9 +9857,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", - "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", + "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9416,15 +9870,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", - "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz", + "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.48.1", - "@typescript-eslint/tsconfig-utils": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", + "@typescript-eslint/project-service": "8.49.0", + "@typescript-eslint/tsconfig-utils": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -9467,15 +9921,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", - "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz", + "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1" + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9490,12 +9944,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", - "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz", + "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/types": "8.49.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -13044,12 +13498,12 @@ } }, "node_modules/eslint-config-next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.7.tgz", - "integrity": "sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ==", + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.8.tgz", + "integrity": "sha512-8J5cOAboXIV3f8OD6BOyj7Fik6n/as7J4MboiUSExWruf/lCu1OPR3ZVSdnta6WhzebrmAATEmNSBZsLWA6kbg==", "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.0.7", + "@next/eslint-plugin-next": "16.0.8", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -14243,12 +14697,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "license": "MIT" - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -22335,15 +22783,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", - "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.49.0.tgz", + "integrity": "sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==", "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.1", - "@typescript-eslint/parser": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1" + "@typescript-eslint/eslint-plugin": "8.49.0", + "@typescript-eslint/parser": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/server/lib/calculateUserClientsForOrgs.ts b/server/lib/calculateUserClientsForOrgs.ts index f7666a36..9cdae547 100644 --- a/server/lib/calculateUserClientsForOrgs.ts +++ b/server/lib/calculateUserClientsForOrgs.ts @@ -166,7 +166,7 @@ export async function calculateUserClientsForOrgs( ]; // Get next available subnet - const newSubnet = await getNextAvailableClientSubnet(orgId); + const newSubnet = await getNextAvailableClientSubnet(orgId, transaction); if (!newSubnet) { logger.warn( `Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no available subnet found` diff --git a/server/lib/ip.ts b/server/lib/ip.ts index f9b3cb61..d367a018 100644 --- a/server/lib/ip.ts +++ b/server/lib/ip.ts @@ -244,7 +244,8 @@ export function isIpInCidr(ip: string, cidr: string): boolean { } export async function getNextAvailableClientSubnet( - orgId: string + orgId: string, + transaction: Transaction | typeof db = db ): Promise { const [org] = await db.select().from(orgs).where(eq(orgs.orgId, orgId)); diff --git a/server/lib/rebuildClientAssociations.ts b/server/lib/rebuildClientAssociations.ts index 134cbc06..9095b9bc 100644 --- a/server/lib/rebuildClientAssociations.ts +++ b/server/lib/rebuildClientAssociations.ts @@ -701,11 +701,45 @@ async function handleSubnetProxyTargetUpdates( } for (const client of removedClients) { + // Check if this client still has access to another resource on this site with the same destination + const destinationStillInUse = await trx + .select() + .from(siteResources) + .innerJoin( + clientSiteResourcesAssociationsCache, + eq( + clientSiteResourcesAssociationsCache.siteResourceId, + siteResources.siteResourceId + ) + ) + .where( + and( + eq( + clientSiteResourcesAssociationsCache.clientId, + client.clientId + ), + eq(siteResources.siteId, siteResource.siteId), + eq( + siteResources.destination, + siteResource.destination + ), + ne( + siteResources.siteResourceId, + siteResource.siteResourceId + ) + ) + ); + + // Only remove remote subnet if no other resource uses the same destination + const remoteSubnetsToRemove = destinationStillInUse.length > 0 + ? [] + : generateRemoteSubnets([siteResource]); + olmJobs.push( removePeerData( client.clientId, siteResource.siteId, - generateRemoteSubnets([siteResource]), + remoteSubnetsToRemove, generateAliasConfig([siteResource]) ) ); @@ -1213,12 +1247,46 @@ async function handleMessagesForClientResources( } try { + // Check if this client still has access to another resource on this site with the same destination + const destinationStillInUse = await trx + .select() + .from(siteResources) + .innerJoin( + clientSiteResourcesAssociationsCache, + eq( + clientSiteResourcesAssociationsCache.siteResourceId, + siteResources.siteResourceId + ) + ) + .where( + and( + eq( + clientSiteResourcesAssociationsCache.clientId, + client.clientId + ), + eq(siteResources.siteId, resource.siteId), + eq( + siteResources.destination, + resource.destination + ), + ne( + siteResources.siteResourceId, + resource.siteResourceId + ) + ) + ); + + // Only remove remote subnet if no other resource uses the same destination + const remoteSubnetsToRemove = destinationStillInUse.length > 0 + ? [] + : generateRemoteSubnets([resource]); + // Remove peer data from olm olmJobs.push( removePeerData( client.clientId, resource.siteId, - generateRemoteSubnets([resource]), + remoteSubnetsToRemove, generateAliasConfig([resource]) ) ); diff --git a/server/private/lib/traefik/getTraefikConfig.ts b/server/private/lib/traefik/getTraefikConfig.ts index 2d0e3ddb..8060ccad 100644 --- a/server/private/lib/traefik/getTraefikConfig.ts +++ b/server/private/lib/traefik/getTraefikConfig.ts @@ -189,7 +189,7 @@ export async function getTraefikConfig( ); if (!validation.isValid) { - logger.error( + logger.debug( `Invalid path rewrite configuration for resource ${resourceId}: ${validation.error}` ); return; diff --git a/server/private/routers/gerbil/receiveBandwidth.ts b/server/private/routers/gerbil/receiveBandwidth.ts deleted file mode 100644 index de0b2d2b..00000000 --- a/server/private/routers/gerbil/receiveBandwidth.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - diff --git a/server/private/routers/ws/ws.ts b/server/private/routers/ws/ws.ts index 41c400cd..f3f4c8fd 100644 --- a/server/private/routers/ws/ws.ts +++ b/server/private/routers/ws/ws.ts @@ -55,9 +55,9 @@ const processMessage = async ( try { const message: WSMessage = JSON.parse(data.toString()); - logger.debug( - `Processing message from ${clientType.toUpperCase()} ID: ${clientId}, type: ${message.type}` - ); + // logger.debug( + // `Processing message from ${clientType.toUpperCase()} ID: ${clientId}, type: ${message.type}` + // ); if (!message.type || typeof message.type !== "string") { throw new Error("Invalid message format: missing or invalid type"); diff --git a/server/routers/auth/startDeviceWebAuth.ts b/server/routers/auth/startDeviceWebAuth.ts index 925df67f..85fb5262 100644 --- a/server/routers/auth/startDeviceWebAuth.ts +++ b/server/routers/auth/startDeviceWebAuth.ts @@ -13,10 +13,12 @@ import { maxmindLookup } from "@server/db/maxmind"; import { encodeHexLowerCase } from "@oslojs/encoding"; import { sha256 } from "@oslojs/crypto/sha2"; -const bodySchema = z.object({ - deviceName: z.string().optional(), - applicationName: z.string().min(1, "Application name is required") -}).strict(); +const bodySchema = z + .object({ + deviceName: z.string().optional(), + applicationName: z.string().min(1, "Application name is required") + }) + .strict(); export type StartDeviceWebAuthBody = z.infer; @@ -34,14 +36,12 @@ function generateDeviceCode(): string { // Helper function to hash device code before storing in database function hashDeviceCode(code: string): string { - return encodeHexLowerCase( - sha256(new TextEncoder().encode(code)) - ); + return encodeHexLowerCase(sha256(new TextEncoder().encode(code))); } // Helper function to extract IP from request function extractIpFromRequest(req: Request): string | undefined { - const ip = req.ip || req.socket.remoteAddress; + const ip = req.ip; if (!ip) { return undefined; } @@ -75,10 +75,10 @@ async function getCityFromIp(ip: string): Promise { return undefined; } - // MaxMind CountryResponse doesn't include city by default - // If city data is available, it would be in result.city?.names?.en - // But since we're using CountryResponse type, we'll just return undefined - // The user said "don't do this if not easy", so we'll skip city for now + if (result.country) { + return result.country.names?.en || result.country.iso_code; + } + return undefined; } catch (error) { logger.debug("Failed to get city from IP", error); diff --git a/server/routers/client/targets.ts b/server/routers/client/targets.ts index c9bb910b..9887a454 100644 --- a/server/routers/client/targets.ts +++ b/server/routers/client/targets.ts @@ -1,5 +1,5 @@ import { sendToClient } from "#dynamic/routers/ws"; -import { db, olms } from "@server/db"; +import { db, olms, Transaction } from "@server/db"; import { Alias, SubnetProxyTarget } from "@server/lib/ip"; import logger from "@server/logger"; import { eq } from "drizzle-orm"; diff --git a/server/routers/gerbil/receiveBandwidth.ts b/server/routers/gerbil/receiveBandwidth.ts index ffbd05c1..297e7c02 100644 --- a/server/routers/gerbil/receiveBandwidth.ts +++ b/server/routers/gerbil/receiveBandwidth.ts @@ -14,12 +14,55 @@ import { build } from "@server/build"; // Track sites that are already offline to avoid unnecessary queries const offlineSites = new Set(); +// Retry configuration for deadlock handling +const MAX_RETRIES = 3; +const BASE_DELAY_MS = 50; + interface PeerBandwidth { publicKey: string; bytesIn: number; bytesOut: number; } +/** + * Check if an error is a deadlock error + */ +function isDeadlockError(error: any): boolean { + return ( + error?.code === "40P01" || + error?.cause?.code === "40P01" || + (error?.message && error.message.includes("deadlock")) + ); +} + +/** + * Execute a function with retry logic for deadlock handling + */ +async function withDeadlockRetry( + operation: () => Promise, + context: string +): Promise { + let attempt = 0; + while (true) { + try { + return await operation(); + } catch (error: any) { + if (isDeadlockError(error) && attempt < MAX_RETRIES) { + attempt++; + const baseDelay = Math.pow(2, attempt - 1) * BASE_DELAY_MS; + const jitter = Math.random() * baseDelay; + const delay = baseDelay + jitter; + logger.warn( + `Deadlock detected in ${context}, retrying attempt ${attempt}/${MAX_RETRIES} after ${delay.toFixed(0)}ms` + ); + await new Promise((resolve) => setTimeout(resolve, delay)); + continue; + } + throw error; + } + } +} + export const receiveBandwidth = async ( req: Request, res: Response, @@ -60,201 +103,208 @@ export async function updateSiteBandwidth( const currentTime = new Date(); const oneMinuteAgo = new Date(currentTime.getTime() - 60000); // 1 minute ago - // logger.debug(`Received data: ${JSON.stringify(bandwidthData)}`); + // Sort bandwidth data by publicKey to ensure consistent lock ordering across all instances + // This is critical for preventing deadlocks when multiple instances update the same sites + const sortedBandwidthData = [...bandwidthData].sort((a, b) => + a.publicKey.localeCompare(b.publicKey) + ); - await db.transaction(async (trx) => { - // First, handle sites that are actively reporting bandwidth - const activePeers = bandwidthData.filter((peer) => peer.bytesIn > 0); // Bytesout will have data as it tries to send keep alive messages + // First, handle sites that are actively reporting bandwidth + const activePeers = sortedBandwidthData.filter((peer) => peer.bytesIn > 0); - if (activePeers.length > 0) { - // Remove any active peers from offline tracking since they're sending data - activePeers.forEach((peer) => offlineSites.delete(peer.publicKey)); + // Aggregate usage data by organization (collected outside transaction) + const orgUsageMap = new Map(); + const orgUptimeMap = new Map(); - // Aggregate usage data by organization - const orgUsageMap = new Map(); - const orgUptimeMap = new Map(); + if (activePeers.length > 0) { + // Remove any active peers from offline tracking since they're sending data + activePeers.forEach((peer) => offlineSites.delete(peer.publicKey)); - // Update all active sites with bandwidth data and get the site data in one operation - const updatedSites = []; - for (const peer of activePeers) { - const [updatedSite] = await trx - .update(sites) - .set({ - megabytesOut: sql`${sites.megabytesOut} + ${peer.bytesIn}`, - megabytesIn: sql`${sites.megabytesIn} + ${peer.bytesOut}`, - lastBandwidthUpdate: currentTime.toISOString(), - online: true - }) - .where(eq(sites.pubKey, peer.publicKey)) - .returning({ - online: sites.online, - orgId: sites.orgId, - siteId: sites.siteId, - lastBandwidthUpdate: sites.lastBandwidthUpdate - }); + // Update each active site individually with retry logic + // This reduces transaction scope and allows retries per-site + for (const peer of activePeers) { + try { + const updatedSite = await withDeadlockRetry(async () => { + const [result] = await db + .update(sites) + .set({ + megabytesOut: sql`${sites.megabytesOut} + ${peer.bytesIn}`, + megabytesIn: sql`${sites.megabytesIn} + ${peer.bytesOut}`, + lastBandwidthUpdate: currentTime.toISOString(), + online: true + }) + .where(eq(sites.pubKey, peer.publicKey)) + .returning({ + online: sites.online, + orgId: sites.orgId, + siteId: sites.siteId, + lastBandwidthUpdate: sites.lastBandwidthUpdate + }); + return result; + }, `update active site ${peer.publicKey}`); if (updatedSite) { if (exitNodeId) { - if ( - await checkExitNodeOrg( - exitNodeId, - updatedSite.orgId, - trx - ) - ) { - // not allowed + const notAllowed = await checkExitNodeOrg( + exitNodeId, + updatedSite.orgId + ); + if (notAllowed) { logger.warn( `Exit node ${exitNodeId} is not allowed for org ${updatedSite.orgId}` ); - // THIS SHOULD TRIGGER THE TRANSACTION TO FAIL? - throw new Error("Exit node not allowed"); + // Skip this site but continue processing others + continue; } } - updatedSites.push({ ...updatedSite, peer }); - } - } - - // Calculate org usage aggregations using the updated site data - for (const { peer, ...site } of updatedSites) { - // Aggregate bandwidth usage for the org - const totalBandwidth = peer.bytesIn + peer.bytesOut; - const currentOrgUsage = orgUsageMap.get(site.orgId) || 0; - orgUsageMap.set(site.orgId, currentOrgUsage + totalBandwidth); - - // Add 10 seconds of uptime for each active site - const currentOrgUptime = orgUptimeMap.get(site.orgId) || 0; - orgUptimeMap.set(site.orgId, currentOrgUptime + 10 / 60); // Store in minutes and jut add 10 seconds - } - - if (calcUsageAndLimits) { - // REMOTE EXIT NODES DO NOT COUNT TOWARDS USAGE - // Process all usage updates sequentially by organization to reduce deadlock risk - const allOrgIds = new Set([...orgUsageMap.keys(), ...orgUptimeMap.keys()]); - - for (const orgId of allOrgIds) { - try { - // Process bandwidth usage for this org - const totalBandwidth = orgUsageMap.get(orgId); - if (totalBandwidth) { - const bandwidthUsage = await usageService.add( - orgId, - FeatureId.EGRESS_DATA_MB, - totalBandwidth, - trx - ); - if (bandwidthUsage) { - usageService - .checkLimitSet( - orgId, - true, - FeatureId.EGRESS_DATA_MB, - bandwidthUsage, - trx - ) - .catch((error: any) => { - logger.error( - `Error checking bandwidth limits for org ${orgId}:`, - error - ); - }); - } - } - - // Process uptime usage for this org - const totalUptime = orgUptimeMap.get(orgId); - if (totalUptime) { - const uptimeUsage = await usageService.add( - orgId, - FeatureId.SITE_UPTIME, - totalUptime, - trx - ); - if (uptimeUsage) { - usageService - .checkLimitSet( - orgId, - true, - FeatureId.SITE_UPTIME, - uptimeUsage, - trx - ) - .catch((error: any) => { - logger.error( - `Error checking uptime limits for org ${orgId}:`, - error - ); - }); - } - } - } catch (error) { - logger.error( - `Error processing usage for org ${orgId}:`, - error - ); - // Don't break the loop, continue with other orgs - } + // Aggregate bandwidth usage for the org + const totalBandwidth = peer.bytesIn + peer.bytesOut; + const currentOrgUsage = orgUsageMap.get(updatedSite.orgId) || 0; + orgUsageMap.set(updatedSite.orgId, currentOrgUsage + totalBandwidth); + + // Add 10 seconds of uptime for each active site + const currentOrgUptime = orgUptimeMap.get(updatedSite.orgId) || 0; + orgUptimeMap.set(updatedSite.orgId, currentOrgUptime + 10 / 60); } + } catch (error) { + logger.error( + `Failed to update bandwidth for site ${peer.publicKey}:`, + error + ); + // Continue with other sites } } + } - // Handle sites that reported zero bandwidth but need online status updated - const zeroBandwidthPeers = bandwidthData.filter( - (peer) => peer.bytesIn === 0 && !offlineSites.has(peer.publicKey) // Bytesout will have data as it tries to send keep alive messages - ); + // Process usage updates outside of site update transactions + // This separates the concerns and reduces lock contention + if (calcUsageAndLimits && (orgUsageMap.size > 0 || orgUptimeMap.size > 0)) { + // Sort org IDs to ensure consistent lock ordering + const allOrgIds = [...new Set([...orgUsageMap.keys(), ...orgUptimeMap.keys()])].sort(); - if (zeroBandwidthPeers.length > 0) { - const zeroBandwidthSites = await trx - .select() - .from(sites) - .where( - inArray( - sites.pubKey, - zeroBandwidthPeers.map((p) => p.publicKey) - ) - ); - - for (const site of zeroBandwidthSites) { - let newOnlineStatus = site.online; - - // Check if site should go offline based on last bandwidth update WITH DATA - if (site.lastBandwidthUpdate) { - const lastUpdateWithData = new Date( - site.lastBandwidthUpdate + for (const orgId of allOrgIds) { + try { + // Process bandwidth usage for this org + const totalBandwidth = orgUsageMap.get(orgId); + if (totalBandwidth) { + const bandwidthUsage = await usageService.add( + orgId, + FeatureId.EGRESS_DATA_MB, + totalBandwidth ); - if (lastUpdateWithData < oneMinuteAgo) { - newOnlineStatus = false; + if (bandwidthUsage) { + // Fire and forget - don't block on limit checking + usageService + .checkLimitSet( + orgId, + true, + FeatureId.EGRESS_DATA_MB, + bandwidthUsage + ) + .catch((error: any) => { + logger.error( + `Error checking bandwidth limits for org ${orgId}:`, + error + ); + }); } - } else { - // No previous data update recorded, set to offline - newOnlineStatus = false; } - // Always update lastBandwidthUpdate to show this instance is receiving reports - // Only update online status if it changed - if (site.online !== newOnlineStatus) { - const [updatedSite] = await trx - .update(sites) - .set({ - online: newOnlineStatus - }) - .where(eq(sites.siteId, site.siteId)) - .returning(); + // Process uptime usage for this org + const totalUptime = orgUptimeMap.get(orgId); + if (totalUptime) { + const uptimeUsage = await usageService.add( + orgId, + FeatureId.SITE_UPTIME, + totalUptime + ); + if (uptimeUsage) { + // Fire and forget - don't block on limit checking + usageService + .checkLimitSet( + orgId, + true, + FeatureId.SITE_UPTIME, + uptimeUsage + ) + .catch((error: any) => { + logger.error( + `Error checking uptime limits for org ${orgId}:`, + error + ); + }); + } + } + } catch (error) { + logger.error( + `Error processing usage for org ${orgId}:`, + error + ); + // Continue with other orgs + } + } + } + + // Handle sites that reported zero bandwidth but need online status updated + const zeroBandwidthPeers = sortedBandwidthData.filter( + (peer) => peer.bytesIn === 0 && !offlineSites.has(peer.publicKey) + ); + + if (zeroBandwidthPeers.length > 0) { + // Fetch all zero bandwidth sites in one query + const zeroBandwidthSites = await db + .select() + .from(sites) + .where( + inArray( + sites.pubKey, + zeroBandwidthPeers.map((p) => p.publicKey) + ) + ); + + // Sort by siteId to ensure consistent lock ordering + const sortedZeroBandwidthSites = zeroBandwidthSites.sort( + (a, b) => a.siteId - b.siteId + ); + + for (const site of sortedZeroBandwidthSites) { + let newOnlineStatus = site.online; + + // Check if site should go offline based on last bandwidth update WITH DATA + if (site.lastBandwidthUpdate) { + const lastUpdateWithData = new Date(site.lastBandwidthUpdate); + if (lastUpdateWithData < oneMinuteAgo) { + newOnlineStatus = false; + } + } else { + // No previous data update recorded, set to offline + newOnlineStatus = false; + } + + // Only update online status if it changed + if (site.online !== newOnlineStatus) { + try { + const updatedSite = await withDeadlockRetry(async () => { + const [result] = await db + .update(sites) + .set({ + online: newOnlineStatus + }) + .where(eq(sites.siteId, site.siteId)) + .returning(); + return result; + }, `update offline status for site ${site.siteId}`); if (updatedSite && exitNodeId) { - if ( - await checkExitNodeOrg( - exitNodeId, - updatedSite.orgId, - trx - ) - ) { - // not allowed + const notAllowed = await checkExitNodeOrg( + exitNodeId, + updatedSite.orgId + ); + if (notAllowed) { logger.warn( `Exit node ${exitNodeId} is not allowed for org ${updatedSite.orgId}` ); - // THIS SHOULD TRIGGER THE TRANSACTION TO FAIL? - throw new Error("Exit node not allowed"); } } @@ -262,8 +312,14 @@ export async function updateSiteBandwidth( if (!newOnlineStatus && site.pubKey) { offlineSites.add(site.pubKey); } + } catch (error) { + logger.error( + `Failed to update offline status for site ${site.siteId}:`, + error + ); + // Continue with other sites } } } - }); + } } diff --git a/server/routers/newt/getNewtToken.ts b/server/routers/newt/getNewtToken.ts index 3bf45dcf..63797358 100644 --- a/server/routers/newt/getNewtToken.ts +++ b/server/routers/newt/getNewtToken.ts @@ -15,6 +15,7 @@ import { import { verifyPassword } from "@server/auth/password"; import logger from "@server/logger"; import config from "@server/lib/config"; +import { APP_VERSION } from "@server/lib/consts"; export const newtGetTokenBodySchema = z.object({ newtId: z.string(), @@ -94,9 +95,10 @@ export async function getNewtToken( const resToken = generateSessionToken(); await createNewtSession(resToken, existingNewt.newtId); - return response<{ token: string }>(res, { + return response<{ token: string; serverVersion: string }>(res, { data: { - token: resToken + token: resToken, + serverVersion: APP_VERSION }, success: true, error: false, diff --git a/server/routers/olm/getOlmToken.ts b/server/routers/olm/getOlmToken.ts index 9cd77c89..3852b00e 100644 --- a/server/routers/olm/getOlmToken.ts +++ b/server/routers/olm/getOlmToken.ts @@ -22,6 +22,7 @@ import { import { verifyPassword } from "@server/auth/password"; import logger from "@server/logger"; import config from "@server/lib/config"; +import { APP_VERSION } from "@server/lib/consts"; export const olmGetTokenBodySchema = z.object({ olmId: z.string(), @@ -205,10 +206,12 @@ export async function getOlmToken( return response<{ token: string; exitNodes: { publicKey: string; endpoint: string }[]; + serverVersion: string; }>(res, { data: { token: resToken, - exitNodes: exitNodesHpData + exitNodes: exitNodesHpData, + serverVersion: APP_VERSION }, success: true, error: false, diff --git a/server/setup/clearStaleData.ts b/server/setup/clearStaleData.ts index 2e54656c..8c7e85f0 100644 --- a/server/setup/clearStaleData.ts +++ b/server/setup/clearStaleData.ts @@ -1,5 +1,5 @@ import { build } from "@server/build"; -import { db, sessionTransferToken } from "@server/db"; +import { db, deviceWebAuthCodes, sessionTransferToken } from "@server/db"; import { emailVerificationCodes, newtSessions, @@ -89,4 +89,12 @@ export async function clearStaleData() { logger.warn("Error clearing expired sessionTransferToken:", e); } } + + try { + await db + .delete(deviceWebAuthCodes) + .where(lt(deviceWebAuthCodes.expiresAt, new Date().getTime())); + } catch (e) { + logger.warn("Error clearing expired deviceWebAuthCodes:", e); + } } diff --git a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx index 0cc84b27..4f66b7f8 100644 --- a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx @@ -198,27 +198,25 @@ export default function CredentialsPage() { {build !== "oss" && ( -
- - -
+ +
)} diff --git a/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx b/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx index 881e6384..e75aa3eb 100644 --- a/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx @@ -182,27 +182,25 @@ export default function CredentialsPage() { {build !== "oss" && ( -
- - -
+ +
)} @@ -229,9 +227,7 @@ export default function CredentialsPage() { )}

- {t( - "clientRegenerateAndDisconnectWarning" - )} + {t("clientRegenerateAndDisconnectWarning")}

) : ( @@ -241,9 +237,7 @@ export default function CredentialsPage() { "clientRegenerateCredentialsConfirmation" )}

-

- {t("clientRegenerateCredentialsWarning")} -

+

{t("clientRegenerateCredentialsWarning")}

)} diff --git a/src/app/[orgId]/settings/clients/machine/create/page.tsx b/src/app/[orgId]/settings/clients/machine/create/page.tsx index efad8ffc..05ace912 100644 --- a/src/app/[orgId]/settings/clients/machine/create/page.tsx +++ b/src/app/[orgId]/settings/clients/machine/create/page.tsx @@ -136,7 +136,7 @@ export default function Page() { All: [ { title: t("install"), - command: `curl -fsSL https://pangolin.net/get-olm.sh | bash` + command: `curl -fsSL https://static.pangolin.net/get-olm.sh | bash` }, { title: t("run"), diff --git a/src/app/[orgId]/settings/resources/proxy/[niceId]/proxy/page.tsx b/src/app/[orgId]/settings/resources/proxy/[niceId]/proxy/page.tsx index 476ac6ab..00f487ea 100644 --- a/src/app/[orgId]/settings/resources/proxy/[niceId]/proxy/page.tsx +++ b/src/app/[orgId]/settings/resources/proxy/[niceId]/proxy/page.tsx @@ -931,9 +931,10 @@ export default function ReverseProxyTargets(props: { openHealthCheckDialog(row.original) } > - -
- {getStatusIcon(status)} +
+ {getStatusText(status)}
diff --git a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx index b2b526ab..6258cd69 100644 --- a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx @@ -265,27 +265,25 @@ export default function CredentialsPage() { {build !== "oss" && ( -
- - -
+ +
)} diff --git a/src/app/[orgId]/settings/sites/create/page.tsx b/src/app/[orgId]/settings/sites/create/page.tsx index be3d5e68..f4ea4f05 100644 --- a/src/app/[orgId]/settings/sites/create/page.tsx +++ b/src/app/[orgId]/settings/sites/create/page.tsx @@ -233,7 +233,7 @@ export default function Page() { All: [ { title: t("install"), - command: `curl -fsSL https://pangolin.net/get-newt.sh | bash` + command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` }, { title: t("run"), diff --git a/src/components/ProductUpdates.tsx b/src/components/ProductUpdates.tsx index f0857160..dae64480 100644 --- a/src/components/ProductUpdates.tsx +++ b/src/components/ProductUpdates.tsx @@ -20,6 +20,7 @@ import { import { useTranslations } from "next-intl"; import { Transition } from "@headlessui/react"; import * as React from "react"; +import { gt, valid } from "semver"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; import { Button } from "./ui/button"; import { Badge } from "./ui/badge"; @@ -72,11 +73,15 @@ export default function ProductUpdates({ if (!data) return null; + const latestVersion = data?.latestVersion?.data?.pangolin.latestVersion; + const currentVersion = env.app.version; + const showNewVersionPopup = Boolean( - data?.latestVersion?.data && - ignoredVersionUpdate !== - data.latestVersion.data?.pangolin.latestVersion && - env.app.version !== data.latestVersion.data?.pangolin.latestVersion + latestVersion && + valid(latestVersion) && + valid(currentVersion) && + ignoredVersionUpdate !== latestVersion && + gt(latestVersion, currentVersion) ); const filteredUpdates = data.updates.filter( diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 78f20b0a..194d8b46 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -66,7 +66,7 @@ export function SettingsSectionFooter({ children: React.ReactNode; }) { return ( -
+
{children}
); diff --git a/statement-breakpoint b/statement-breakpoint deleted file mode 100644 index e69de29b..00000000