mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-22 02:28:26 +02:00
Ready for testing
This commit is contained in:
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Опити за повторно",
|
"retryAttempts": "Опити за повторно",
|
||||||
"expectedResponseCodes": "Очаквани кодове за отговор",
|
"expectedResponseCodes": "Очаквани кодове за отговор",
|
||||||
"expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.",
|
"expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.",
|
||||||
"customHeaders": "Персонализирани заглавия",
|
"customRequestHeaders": "Персонализирани заглавия",
|
||||||
"customHeadersDescription": "Add custom headers to be sent when proxying requests. One per line in the format Header-Name: value",
|
"customRequestHeadersDescription": "Add custom headers to be sent when proxying requests. One per line in the format Header-Name: value",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Заглавията трябва да бъдат във формат: Име на заглавието: стойност.",
|
"headersValidationError": "Заглавията трябва да бъдат във формат: Име на заглавието: стойност.",
|
||||||
"saveHealthCheck": "Запазване на проверка на здравето",
|
"saveHealthCheck": "Запазване на проверка на здравето",
|
||||||
"healthCheckSaved": "Проверка на здравето е запазена",
|
"healthCheckSaved": "Проверка на здравето е запазена",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Opakovat pokusy",
|
"retryAttempts": "Opakovat pokusy",
|
||||||
"expectedResponseCodes": "Očekávané kódy odezvy",
|
"expectedResponseCodes": "Očekávané kódy odezvy",
|
||||||
"expectedResponseCodesDescription": "HTTP kód stavu, který označuje zdravý stav. Ponecháte-li prázdné, 200-300 je považováno za zdravé.",
|
"expectedResponseCodesDescription": "HTTP kód stavu, který označuje zdravý stav. Ponecháte-li prázdné, 200-300 je považováno za zdravé.",
|
||||||
"customHeaders": "Vlastní záhlaví",
|
"customRequestHeaders": "Vlastní záhlaví",
|
||||||
"customHeadersDescription": "Záhlaví oddělená nová řádka: hodnota",
|
"customRequestHeadersDescription": "Záhlaví oddělená nová řádka: hodnota",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Headers must be in the format: Header-Name: value.",
|
"headersValidationError": "Headers must be in the format: Header-Name: value.",
|
||||||
"saveHealthCheck": "Uložit kontrolu stavu",
|
"saveHealthCheck": "Uložit kontrolu stavu",
|
||||||
"healthCheckSaved": "Kontrola stavu uložena",
|
"healthCheckSaved": "Kontrola stavu uložena",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Wiederholungsversuche",
|
"retryAttempts": "Wiederholungsversuche",
|
||||||
"expectedResponseCodes": "Erwartete Antwortcodes",
|
"expectedResponseCodes": "Erwartete Antwortcodes",
|
||||||
"expectedResponseCodesDescription": "HTTP-Statuscode, der einen gesunden Zustand anzeigt. Wenn leer gelassen, wird 200-300 als gesund angesehen.",
|
"expectedResponseCodesDescription": "HTTP-Statuscode, der einen gesunden Zustand anzeigt. Wenn leer gelassen, wird 200-300 als gesund angesehen.",
|
||||||
"customHeaders": "Eigene Kopfzeilen",
|
"customRequestHeaders": "Eigene Kopfzeilen",
|
||||||
"customHeadersDescription": "Header neue Zeile getrennt: Header-Name: Wert",
|
"customRequestHeadersDescription": "Header neue Zeile getrennt: Header-Name: Wert",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Header müssen im Format Header-Name: Wert sein.",
|
"headersValidationError": "Header müssen im Format Header-Name: Wert sein.",
|
||||||
"saveHealthCheck": "Gesundheits-Check speichern",
|
"saveHealthCheck": "Gesundheits-Check speichern",
|
||||||
"healthCheckSaved": "Gesundheits-Check gespeichert",
|
"healthCheckSaved": "Gesundheits-Check gespeichert",
|
||||||
|
|||||||
+4
-2
@@ -1994,8 +1994,10 @@
|
|||||||
"retryAttempts": "Retry Attempts",
|
"retryAttempts": "Retry Attempts",
|
||||||
"expectedResponseCodes": "Expected Response Codes",
|
"expectedResponseCodes": "Expected Response Codes",
|
||||||
"expectedResponseCodesDescription": "HTTP status code that indicates healthy status. If left blank, 200-300 is considered healthy.",
|
"expectedResponseCodesDescription": "HTTP status code that indicates healthy status. If left blank, 200-300 is considered healthy.",
|
||||||
"customHeaders": "Custom Request Headers",
|
"customRequestHeaders": "Custom Request Headers",
|
||||||
"customHeadersDescription": "Request headers sent to the downstream targets. Headers new line separated: Header-Name: value",
|
"customRequestHeadersDescription": "Request headers sent to the downstream targets. One per line: Header-Name: value",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Headers must be in the format: Header-Name: value",
|
"headersValidationError": "Headers must be in the format: Header-Name: value",
|
||||||
"saveHealthCheck": "Save Health Check",
|
"saveHealthCheck": "Save Health Check",
|
||||||
"healthCheckSaved": "Health Check Saved",
|
"healthCheckSaved": "Health Check Saved",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Intentos de Reintento",
|
"retryAttempts": "Intentos de Reintento",
|
||||||
"expectedResponseCodes": "Códigos de respuesta esperados",
|
"expectedResponseCodes": "Códigos de respuesta esperados",
|
||||||
"expectedResponseCodesDescription": "Código de estado HTTP que indica un estado saludable. Si se deja en blanco, se considera saludable de 200 a 300.",
|
"expectedResponseCodesDescription": "Código de estado HTTP que indica un estado saludable. Si se deja en blanco, se considera saludable de 200 a 300.",
|
||||||
"customHeaders": "Cabeceras personalizadas",
|
"customRequestHeaders": "Cabeceras personalizadas",
|
||||||
"customHeadersDescription": "Nueva línea de cabeceras separada: Nombre de cabecera: valor",
|
"customRequestHeadersDescription": "Nueva línea de cabeceras separada: Nombre de cabecera: valor",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Los encabezados deben estar en el formato: Nombre de cabecera: valor.",
|
"headersValidationError": "Los encabezados deben estar en el formato: Nombre de cabecera: valor.",
|
||||||
"saveHealthCheck": "Guardar Chequeo de Salud",
|
"saveHealthCheck": "Guardar Chequeo de Salud",
|
||||||
"healthCheckSaved": "Chequeo de Salud Guardado",
|
"healthCheckSaved": "Chequeo de Salud Guardado",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Tentatives de réessai",
|
"retryAttempts": "Tentatives de réessai",
|
||||||
"expectedResponseCodes": "Codes de réponse attendus",
|
"expectedResponseCodes": "Codes de réponse attendus",
|
||||||
"expectedResponseCodesDescription": "Code de statut HTTP indiquant un état de santé satisfaisant. Si non renseigné, 200-300 est considéré comme satisfaisant.",
|
"expectedResponseCodesDescription": "Code de statut HTTP indiquant un état de santé satisfaisant. Si non renseigné, 200-300 est considéré comme satisfaisant.",
|
||||||
"customHeaders": "En-têtes personnalisés",
|
"customRequestHeaders": "En-têtes personnalisés",
|
||||||
"customHeadersDescription": "En-têtes séparés par une nouvelle ligne: En-nom: valeur",
|
"customRequestHeadersDescription": "En-têtes séparés par une nouvelle ligne: En-nom: valeur",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Les entêtes doivent être au format : Header-Name: valeur.",
|
"headersValidationError": "Les entêtes doivent être au format : Header-Name: valeur.",
|
||||||
"saveHealthCheck": "Sauvegarder la vérification de l'état de santé",
|
"saveHealthCheck": "Sauvegarder la vérification de l'état de santé",
|
||||||
"healthCheckSaved": "Vérification de l'état de santé enregistrée",
|
"healthCheckSaved": "Vérification de l'état de santé enregistrée",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Tentativi di Riprova",
|
"retryAttempts": "Tentativi di Riprova",
|
||||||
"expectedResponseCodes": "Codici di Risposta Attesi",
|
"expectedResponseCodes": "Codici di Risposta Attesi",
|
||||||
"expectedResponseCodesDescription": "Codice di stato HTTP che indica lo stato di salute. Se lasciato vuoto, considerato sano è compreso tra 200-300.",
|
"expectedResponseCodesDescription": "Codice di stato HTTP che indica lo stato di salute. Se lasciato vuoto, considerato sano è compreso tra 200-300.",
|
||||||
"customHeaders": "Intestazioni Personalizzate",
|
"customRequestHeaders": "Intestazioni Personalizzate",
|
||||||
"customHeadersDescription": "Intestazioni nuova riga separate: Intestazione-Nome: valore",
|
"customRequestHeadersDescription": "Intestazioni nuova riga separate: Intestazione-Nome: valore",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Le intestazioni devono essere nel formato: Intestazione-Nome: valore.",
|
"headersValidationError": "Le intestazioni devono essere nel formato: Intestazione-Nome: valore.",
|
||||||
"saveHealthCheck": "Salva Controllo Salute",
|
"saveHealthCheck": "Salva Controllo Salute",
|
||||||
"healthCheckSaved": "Controllo Salute Salvato",
|
"healthCheckSaved": "Controllo Salute Salvato",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "재시도 횟수",
|
"retryAttempts": "재시도 횟수",
|
||||||
"expectedResponseCodes": "예상 응답 코드",
|
"expectedResponseCodes": "예상 응답 코드",
|
||||||
"expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.",
|
"expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.",
|
||||||
"customHeaders": "사용자 정의 헤더",
|
"customRequestHeaders": "사용자 정의 헤더",
|
||||||
"customHeadersDescription": "헤더는 새 줄로 구분됨: Header-Name: value",
|
"customRequestHeadersDescription": "헤더는 새 줄로 구분됨: Header-Name: value",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "헤더는 형식이어야 합니다: 헤더명: 값.",
|
"headersValidationError": "헤더는 형식이어야 합니다: 헤더명: 값.",
|
||||||
"saveHealthCheck": "상태 확인 저장",
|
"saveHealthCheck": "상태 확인 저장",
|
||||||
"healthCheckSaved": "상태 확인이 저장되었습니다.",
|
"healthCheckSaved": "상태 확인이 저장되었습니다.",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Forsøk på nytt",
|
"retryAttempts": "Forsøk på nytt",
|
||||||
"expectedResponseCodes": "Forventede svarkoder",
|
"expectedResponseCodes": "Forventede svarkoder",
|
||||||
"expectedResponseCodesDescription": "HTTP-statuskode som indikerer sunn status. Hvis den blir stående tom, regnes 200-300 som sunn.",
|
"expectedResponseCodesDescription": "HTTP-statuskode som indikerer sunn status. Hvis den blir stående tom, regnes 200-300 som sunn.",
|
||||||
"customHeaders": "Egendefinerte topptekster",
|
"customRequestHeaders": "Egendefinerte topptekster",
|
||||||
"customHeadersDescription": "Overskrifter som er adskilt med linje: Overskriftsnavn: verdi",
|
"customRequestHeadersDescription": "Overskrifter som er adskilt med linje: Overskriftsnavn: verdi",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Topptekst må være i formatet: header-navn: verdi.",
|
"headersValidationError": "Topptekst må være i formatet: header-navn: verdi.",
|
||||||
"saveHealthCheck": "Lagre Helsekontroll",
|
"saveHealthCheck": "Lagre Helsekontroll",
|
||||||
"healthCheckSaved": "Helsekontroll Lagret",
|
"healthCheckSaved": "Helsekontroll Lagret",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Herhaal Pogingen",
|
"retryAttempts": "Herhaal Pogingen",
|
||||||
"expectedResponseCodes": "Verwachte Reactiecodes",
|
"expectedResponseCodes": "Verwachte Reactiecodes",
|
||||||
"expectedResponseCodesDescription": "HTTP-statuscode die gezonde status aangeeft. Indien leeg wordt 200-300 als gezond beschouwd.",
|
"expectedResponseCodesDescription": "HTTP-statuscode die gezonde status aangeeft. Indien leeg wordt 200-300 als gezond beschouwd.",
|
||||||
"customHeaders": "Aangepaste headers",
|
"customRequestHeaders": "Aangepaste headers",
|
||||||
"customHeadersDescription": "Kopregeleinde: Header-Naam: waarde",
|
"customRequestHeadersDescription": "Kopregeleinde: Header-Naam: waarde",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Headers moeten in het formaat zijn: Header-Naam: waarde.",
|
"headersValidationError": "Headers moeten in het formaat zijn: Header-Naam: waarde.",
|
||||||
"saveHealthCheck": "Opslaan Gezondheidscontrole",
|
"saveHealthCheck": "Opslaan Gezondheidscontrole",
|
||||||
"healthCheckSaved": "Gezondheidscontrole Opgeslagen",
|
"healthCheckSaved": "Gezondheidscontrole Opgeslagen",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Próby Ponowienia",
|
"retryAttempts": "Próby Ponowienia",
|
||||||
"expectedResponseCodes": "Oczekiwane Kody Odpowiedzi",
|
"expectedResponseCodes": "Oczekiwane Kody Odpowiedzi",
|
||||||
"expectedResponseCodesDescription": "Kod statusu HTTP, który wskazuje zdrowy status. Jeśli pozostanie pusty, uznaje się 200-300 za zdrowy.",
|
"expectedResponseCodesDescription": "Kod statusu HTTP, który wskazuje zdrowy status. Jeśli pozostanie pusty, uznaje się 200-300 za zdrowy.",
|
||||||
"customHeaders": "Niestandardowe nagłówki",
|
"customRequestHeaders": "Niestandardowe nagłówki",
|
||||||
"customHeadersDescription": "Nagłówki oddzielone: Nazwa nagłówka: wartość",
|
"customRequestHeadersDescription": "Nagłówki oddzielone: Nazwa nagłówka: wartość",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Nagłówki muszą być w formacie: Nazwa nagłówka: wartość.",
|
"headersValidationError": "Nagłówki muszą być w formacie: Nazwa nagłówka: wartość.",
|
||||||
"saveHealthCheck": "Zapisz Kontrolę Zdrowia",
|
"saveHealthCheck": "Zapisz Kontrolę Zdrowia",
|
||||||
"healthCheckSaved": "Kontrola Zdrowia Zapisana",
|
"healthCheckSaved": "Kontrola Zdrowia Zapisana",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Tentativas de Repetição",
|
"retryAttempts": "Tentativas de Repetição",
|
||||||
"expectedResponseCodes": "Códigos de Resposta Esperados",
|
"expectedResponseCodes": "Códigos de Resposta Esperados",
|
||||||
"expectedResponseCodesDescription": "Código de status HTTP que indica estado saudável. Se deixado em branco, 200-300 é considerado saudável.",
|
"expectedResponseCodesDescription": "Código de status HTTP que indica estado saudável. Se deixado em branco, 200-300 é considerado saudável.",
|
||||||
"customHeaders": "Cabeçalhos Personalizados",
|
"customRequestHeaders": "Cabeçalhos Personalizados",
|
||||||
"customHeadersDescription": "Separados por cabeçalhos da nova linha: Nome do Cabeçalho: valor",
|
"customRequestHeadersDescription": "Separados por cabeçalhos da nova linha: Nome do Cabeçalho: valor",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Cabeçalhos devem estar no formato: Nome do Cabeçalho: valor.",
|
"headersValidationError": "Cabeçalhos devem estar no formato: Nome do Cabeçalho: valor.",
|
||||||
"saveHealthCheck": "Salvar Verificação de Saúde",
|
"saveHealthCheck": "Salvar Verificação de Saúde",
|
||||||
"healthCheckSaved": "Verificação de Saúde Salva",
|
"healthCheckSaved": "Verificação de Saúde Salva",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Количество попыток повторного запроса",
|
"retryAttempts": "Количество попыток повторного запроса",
|
||||||
"expectedResponseCodes": "Ожидаемые коды ответов",
|
"expectedResponseCodes": "Ожидаемые коды ответов",
|
||||||
"expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.",
|
"expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.",
|
||||||
"customHeaders": "Пользовательские заголовки",
|
"customRequestHeaders": "Пользовательские заголовки",
|
||||||
"customHeadersDescription": "Заголовки новой строки, разделённые: название заголовка: значение",
|
"customRequestHeadersDescription": "Заголовки новой строки, разделённые: название заголовка: значение",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Заголовки должны быть в формате: Название заголовка: значение.",
|
"headersValidationError": "Заголовки должны быть в формате: Название заголовка: значение.",
|
||||||
"saveHealthCheck": "Сохранить проверку здоровья",
|
"saveHealthCheck": "Сохранить проверку здоровья",
|
||||||
"healthCheckSaved": "Проверка здоровья сохранена",
|
"healthCheckSaved": "Проверка здоровья сохранена",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "Tekrar Deneme Girişimleri",
|
"retryAttempts": "Tekrar Deneme Girişimleri",
|
||||||
"expectedResponseCodes": "Beklenen Yanıt Kodları",
|
"expectedResponseCodes": "Beklenen Yanıt Kodları",
|
||||||
"expectedResponseCodesDescription": "Sağlıklı durumu gösteren HTTP durum kodu. Boş bırakılırsa, 200-300 arası sağlıklı kabul edilir.",
|
"expectedResponseCodesDescription": "Sağlıklı durumu gösteren HTTP durum kodu. Boş bırakılırsa, 200-300 arası sağlıklı kabul edilir.",
|
||||||
"customHeaders": "Özel Başlıklar",
|
"customRequestHeaders": "Özel Başlıklar",
|
||||||
"customHeadersDescription": "Başlıklar yeni satırla ayrılmış: Başlık-Adı: değer",
|
"customRequestHeadersDescription": "Başlıklar yeni satırla ayrılmış: Başlık-Adı: değer",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Başlıklar şu formatta olmalıdır: Başlık-Adı: değer.",
|
"headersValidationError": "Başlıklar şu formatta olmalıdır: Başlık-Adı: değer.",
|
||||||
"saveHealthCheck": "Sağlık Kontrolünü Kaydet",
|
"saveHealthCheck": "Sağlık Kontrolünü Kaydet",
|
||||||
"healthCheckSaved": "Sağlık Kontrolü Kaydedildi",
|
"healthCheckSaved": "Sağlık Kontrolü Kaydedildi",
|
||||||
|
|||||||
+4
-2
@@ -1964,8 +1964,10 @@
|
|||||||
"retryAttempts": "重试次数",
|
"retryAttempts": "重试次数",
|
||||||
"expectedResponseCodes": "期望响应代码",
|
"expectedResponseCodes": "期望响应代码",
|
||||||
"expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空,200-300 被视为健康。",
|
"expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空,200-300 被视为健康。",
|
||||||
"customHeaders": "自定义标题",
|
"customRequestHeaders": "自定义标题",
|
||||||
"customHeadersDescription": "头部新行分隔:头部名称:值",
|
"customRequestHeadersDescription": "头部新行分隔:头部名称:值",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "头部必须是格式:头部名称:值。",
|
"headersValidationError": "头部必须是格式:头部名称:值。",
|
||||||
"saveHealthCheck": "保存健康检查",
|
"saveHealthCheck": "保存健康检查",
|
||||||
"healthCheckSaved": "健康检查已保存",
|
"healthCheckSaved": "健康检查已保存",
|
||||||
|
|||||||
+4
-2
@@ -1555,8 +1555,10 @@
|
|||||||
"retryAttempts": "重試次數",
|
"retryAttempts": "重試次數",
|
||||||
"expectedResponseCodes": "期望響應代碼",
|
"expectedResponseCodes": "期望響應代碼",
|
||||||
"expectedResponseCodesDescription": "HTTP 狀態碼表示健康狀態。如留空,200-300 被視為健康。",
|
"expectedResponseCodesDescription": "HTTP 狀態碼表示健康狀態。如留空,200-300 被視為健康。",
|
||||||
"customHeaders": "自訂 Headers",
|
"customRequestHeaders": "自訂 Headers",
|
||||||
"customHeadersDescription": "Header 斷行分隔:Header 名稱:值",
|
"customRequestHeadersDescription": "Header 斷行分隔:Header 名稱:值",
|
||||||
|
"customResponseHeaders": "Custom Response Headers",
|
||||||
|
"customResponseHeadersDescription": "Response headers sent back to the client. One per line: Header-Name: value",
|
||||||
"headersValidationError": "Header 必須是格式:Header 名稱:值。",
|
"headersValidationError": "Header 必須是格式:Header 名稱:值。",
|
||||||
"saveHealthCheck": "保存健康檢查",
|
"saveHealthCheck": "保存健康檢查",
|
||||||
"healthCheckSaved": "健康檢查已保存",
|
"healthCheckSaved": "健康檢查已保存",
|
||||||
|
|||||||
Generated
+6
-31
@@ -1058,7 +1058,6 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -3034,7 +3033,6 @@
|
|||||||
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
|
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.21.3 || >=16"
|
"node": "^14.21.3 || >=16"
|
||||||
},
|
},
|
||||||
@@ -6981,7 +6979,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@react-email/text/-/text-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@react-email/text/-/text-0.1.6.tgz",
|
||||||
"integrity": "sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw==",
|
"integrity": "sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
},
|
||||||
@@ -8442,7 +8439,6 @@
|
|||||||
"version": "5.90.21",
|
"version": "5.90.21",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz",
|
||||||
"integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==",
|
"integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.90.20"
|
"@tanstack/query-core": "5.90.20"
|
||||||
},
|
},
|
||||||
@@ -8558,7 +8554,6 @@
|
|||||||
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
|
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
@@ -8906,7 +8901,6 @@
|
|||||||
"integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
|
"integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
"@types/express-serve-static-core": "^5.0.0",
|
"@types/express-serve-static-core": "^5.0.0",
|
||||||
@@ -9002,7 +8996,6 @@
|
|||||||
"integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==",
|
"integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.18.0"
|
"undici-types": "~7.18.0"
|
||||||
}
|
}
|
||||||
@@ -9030,7 +9023,6 @@
|
|||||||
"integrity": "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==",
|
"integrity": "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"pg-protocol": "*",
|
"pg-protocol": "*",
|
||||||
@@ -9056,7 +9048,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -9067,7 +9058,6 @@
|
|||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@@ -9154,7 +9144,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.18.1",
|
"version": "8.18.1",
|
||||||
@@ -9228,7 +9219,6 @@
|
|||||||
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.56.1",
|
"@typescript-eslint/scope-manager": "8.56.1",
|
||||||
"@typescript-eslint/types": "8.56.1",
|
"@typescript-eslint/types": "8.56.1",
|
||||||
@@ -9702,7 +9692,6 @@
|
|||||||
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -10152,7 +10141,6 @@
|
|||||||
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
|
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.26.0"
|
"@babel/types": "^7.26.0"
|
||||||
}
|
}
|
||||||
@@ -10224,7 +10212,6 @@
|
|||||||
"integrity": "sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==",
|
"integrity": "sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
"prebuild-install": "^7.1.1"
|
"prebuild-install": "^7.1.1"
|
||||||
@@ -10353,7 +10340,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -11260,7 +11246,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
@@ -11701,6 +11686,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz",
|
||||||
"integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==",
|
"integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==",
|
||||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
@@ -12335,7 +12321,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
@@ -12421,7 +12406,6 @@
|
|||||||
"integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==",
|
"integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.2",
|
"@eslint-community/regexpp": "^4.12.2",
|
||||||
@@ -12558,7 +12542,6 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -12952,7 +12935,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
||||||
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "^2.0.0",
|
"accepts": "^2.0.0",
|
||||||
"body-parser": "^2.2.1",
|
"body-parser": "^2.2.1",
|
||||||
@@ -15370,6 +15352,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
||||||
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dompurify": "3.2.7",
|
"dompurify": "3.2.7",
|
||||||
"marked": "14.0.0"
|
"marked": "14.0.0"
|
||||||
@@ -15380,6 +15363,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
|
||||||
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
|
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"marked": "bin/marked.js"
|
"marked": "bin/marked.js"
|
||||||
},
|
},
|
||||||
@@ -15468,7 +15452,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/next/-/next-15.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-15.5.15.tgz",
|
||||||
"integrity": "sha512-VSqCrJwtLVGwAVE0Sb/yikrQfkwkZW9p+lL/J4+xe+G3ZA+QnWPqgcfH1tDUEuk9y+pthzzVFp4L/U8JerMfMQ==",
|
"integrity": "sha512-VSqCrJwtLVGwAVE0Sb/yikrQfkwkZW9p+lL/J4+xe+G3ZA+QnWPqgcfH1tDUEuk9y+pthzzVFp4L/U8JerMfMQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "15.5.15",
|
"@next/env": "15.5.15",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
@@ -16428,7 +16411,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
|
||||||
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
|
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.12.0",
|
"pg-connection-string": "^2.12.0",
|
||||||
"pg-pool": "^3.13.0",
|
"pg-pool": "^3.13.0",
|
||||||
@@ -16936,7 +16918,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||||
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -16968,7 +16949,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -17261,7 +17241,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz",
|
||||||
"integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==",
|
"integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
@@ -18723,8 +18702,7 @@
|
|||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
|
||||||
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
|
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
@@ -19199,7 +19177,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -19627,7 +19604,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
|
||||||
"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
|
"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@colors/colors": "^1.6.0",
|
"@colors/colors": "^1.6.0",
|
||||||
"@dabh/diagnostics": "^2.0.8",
|
"@dabh/diagnostics": "^2.0.8",
|
||||||
@@ -19834,7 +19810,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
||||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,8 @@ export const resources = pgTable("resources", {
|
|||||||
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
|
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
|
||||||
onDelete: "set null"
|
onDelete: "set null"
|
||||||
}),
|
}),
|
||||||
headers: text("headers"), // comma-separated list of headers to add to the request
|
requestHeaders: text("requestHeaders"),
|
||||||
|
responseHeaders: text("responseHeaders"),
|
||||||
proxyProtocol: boolean("proxyProtocol").notNull().default(false),
|
proxyProtocol: boolean("proxyProtocol").notNull().default(false),
|
||||||
proxyProtocolVersion: integer("proxyProtocolVersion").default(1),
|
proxyProtocolVersion: integer("proxyProtocolVersion").default(1),
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ export const resources = sqliteTable("resources", {
|
|||||||
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
|
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
|
||||||
onDelete: "set null"
|
onDelete: "set null"
|
||||||
}),
|
}),
|
||||||
headers: text("headers"), // comma-separated list of headers to add to the request
|
requestHeaders: text("requestHeaders"),
|
||||||
|
responseHeaders: text("responseHeaders"),
|
||||||
proxyProtocol: integer("proxyProtocol", { mode: "boolean" })
|
proxyProtocol: integer("proxyProtocol", { mode: "boolean" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(false),
|
.default(false),
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ export async function getTraefikConfig(
|
|||||||
tlsServerName: resources.tlsServerName,
|
tlsServerName: resources.tlsServerName,
|
||||||
setHostHeader: resources.setHostHeader,
|
setHostHeader: resources.setHostHeader,
|
||||||
enableProxy: resources.enableProxy,
|
enableProxy: resources.enableProxy,
|
||||||
headers: resources.headers,
|
requestHeaders: resources.requestHeaders,
|
||||||
|
responseHeaders: resources.responseHeaders,
|
||||||
proxyProtocol: resources.proxyProtocol,
|
proxyProtocol: resources.proxyProtocol,
|
||||||
proxyProtocolVersion: resources.proxyProtocolVersion,
|
proxyProtocolVersion: resources.proxyProtocolVersion,
|
||||||
|
|
||||||
@@ -177,7 +178,8 @@ export async function getTraefikConfig(
|
|||||||
setHostHeader: row.setHostHeader,
|
setHostHeader: row.setHostHeader,
|
||||||
enableProxy: row.enableProxy,
|
enableProxy: row.enableProxy,
|
||||||
targets: [],
|
targets: [],
|
||||||
headers: row.headers,
|
requestHeaders: row.requestHeaders,
|
||||||
|
responseHeaders: row.responseHeaders,
|
||||||
proxyProtocol: row.proxyProtocol,
|
proxyProtocol: row.proxyProtocol,
|
||||||
proxyProtocolVersion: row.proxyProtocolVersion ?? 1,
|
proxyProtocolVersion: row.proxyProtocolVersion ?? 1,
|
||||||
path: row.path, // the targets will all have the same path
|
path: row.path, // the targets will all have the same path
|
||||||
@@ -364,38 +366,59 @@ export async function getTraefikConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle custom headers middleware
|
// Handle custom headers middleware
|
||||||
if (resource.headers || resource.setHostHeader) {
|
if (resource.requestHeaders || resource.responseHeaders || resource.setHostHeader) {
|
||||||
const headersObj: { [key: string]: string } = {};
|
const requestHeadersObj: { [key: string]: string } = {};
|
||||||
|
const responseHeadersObj: { [key: string]: string } = {};
|
||||||
|
|
||||||
if (resource.headers) {
|
if (resource.requestHeaders) {
|
||||||
let headersArr: { name: string; value: string }[] = [];
|
let requestHeadersArr: { name: string; value: string }[] = [];
|
||||||
try {
|
try {
|
||||||
headersArr = JSON.parse(resource.headers) as {
|
requestHeadersArr = JSON.parse(resource.requestHeaders) as {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Failed to parse headers for resource ${resource.resourceId}: ${e}`
|
`Failed to parse requestHeaders for resource ${resource.resourceId}: ${e}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
requestHeadersArr.forEach((header) => {
|
||||||
headersArr.forEach((header) => {
|
requestHeadersObj[header.name] = header.value;
|
||||||
headersObj[header.name] = header.value;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.setHostHeader) {
|
if (resource.setHostHeader) {
|
||||||
headersObj["Host"] = resource.setHostHeader;
|
requestHeadersObj["Host"] = resource.setHostHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(headersObj).length > 0) {
|
if (resource.responseHeaders) {
|
||||||
|
let responseHeadersArr: { name: string; value: string }[] = [];
|
||||||
|
try {
|
||||||
|
responseHeadersArr = JSON.parse(resource.responseHeaders) as {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(
|
||||||
|
`Failed to parse responseHeaders for resource ${resource.resourceId}: ${e}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
responseHeadersArr.forEach((header) => {
|
||||||
|
responseHeadersObj[header.name] = header.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRequestHeaders = Object.keys(requestHeadersObj).length > 0;
|
||||||
|
const hasResponseHeaders = Object.keys(responseHeadersObj).length > 0;
|
||||||
|
|
||||||
|
if (hasRequestHeaders || hasResponseHeaders) {
|
||||||
if (!config_output.http.middlewares) {
|
if (!config_output.http.middlewares) {
|
||||||
config_output.http.middlewares = {};
|
config_output.http.middlewares = {};
|
||||||
}
|
}
|
||||||
config_output.http.middlewares[headersMiddlewareName] = {
|
config_output.http.middlewares[headersMiddlewareName] = {
|
||||||
headers: {
|
headers: {
|
||||||
customRequestHeaders: headersObj
|
...(hasRequestHeaders && { customRequestHeaders: requestHeadersObj }),
|
||||||
|
...(hasResponseHeaders && { customResponseHeaders: responseHeadersObj })
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ export async function getTraefikConfig(
|
|||||||
tlsServerName: resources.tlsServerName,
|
tlsServerName: resources.tlsServerName,
|
||||||
setHostHeader: resources.setHostHeader,
|
setHostHeader: resources.setHostHeader,
|
||||||
enableProxy: resources.enableProxy,
|
enableProxy: resources.enableProxy,
|
||||||
headers: resources.headers,
|
requestHeaders: resources.requestHeaders,
|
||||||
|
responseHeaders: resources.responseHeaders,
|
||||||
proxyProtocol: resources.proxyProtocol,
|
proxyProtocol: resources.proxyProtocol,
|
||||||
proxyProtocolVersion: resources.proxyProtocolVersion,
|
proxyProtocolVersion: resources.proxyProtocolVersion,
|
||||||
wildcard: resources.wildcard,
|
wildcard: resources.wildcard,
|
||||||
@@ -237,7 +238,8 @@ export async function getTraefikConfig(
|
|||||||
setHostHeader: row.setHostHeader,
|
setHostHeader: row.setHostHeader,
|
||||||
enableProxy: row.enableProxy,
|
enableProxy: row.enableProxy,
|
||||||
targets: [],
|
targets: [],
|
||||||
headers: row.headers,
|
requestHeaders: row.requestHeaders,
|
||||||
|
responseHeaders: row.responseHeaders,
|
||||||
proxyProtocol: row.proxyProtocol,
|
proxyProtocol: row.proxyProtocol,
|
||||||
proxyProtocolVersion: row.proxyProtocolVersion ?? 1,
|
proxyProtocolVersion: row.proxyProtocolVersion ?? 1,
|
||||||
path: row.path, // the targets will all have the same path
|
path: row.path, // the targets will all have the same path
|
||||||
@@ -648,40 +650,59 @@ export async function getTraefikConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.headers || resource.setHostHeader) {
|
if (resource.requestHeaders || resource.responseHeaders || resource.setHostHeader) {
|
||||||
// if there are headers, parse them into an object
|
const requestHeadersObj: { [key: string]: string } = {};
|
||||||
const headersObj: { [key: string]: string } = {};
|
const responseHeadersObj: { [key: string]: string } = {};
|
||||||
if (resource.headers) {
|
|
||||||
let headersArr: { name: string; value: string }[] = [];
|
if (resource.requestHeaders) {
|
||||||
|
let requestHeadersArr: { name: string; value: string }[] = [];
|
||||||
try {
|
try {
|
||||||
headersArr = JSON.parse(resource.headers) as {
|
requestHeadersArr = JSON.parse(resource.requestHeaders) as {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Failed to parse headers for resource ${resource.resourceId}: ${e}`
|
`Failed to parse requestHeaders for resource ${resource.resourceId}: ${e}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
requestHeadersArr.forEach((header) => {
|
||||||
headersArr.forEach((header) => {
|
requestHeadersObj[header.name] = header.value;
|
||||||
headersObj[header.name] = header.value;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.setHostHeader) {
|
if (resource.setHostHeader) {
|
||||||
headersObj["Host"] = resource.setHostHeader;
|
requestHeadersObj["Host"] = resource.setHostHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the object is not empty
|
if (resource.responseHeaders) {
|
||||||
if (Object.keys(headersObj).length > 0) {
|
let responseHeadersArr: { name: string; value: string }[] = [];
|
||||||
// Add the headers middleware
|
try {
|
||||||
|
responseHeadersArr = JSON.parse(resource.responseHeaders) as {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(
|
||||||
|
`Failed to parse responseHeaders for resource ${resource.resourceId}: ${e}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
responseHeadersArr.forEach((header) => {
|
||||||
|
responseHeadersObj[header.name] = header.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRequestHeaders = Object.keys(requestHeadersObj).length > 0;
|
||||||
|
const hasResponseHeaders = Object.keys(responseHeadersObj).length > 0;
|
||||||
|
|
||||||
|
if (hasRequestHeaders || hasResponseHeaders) {
|
||||||
if (!config_output.http.middlewares) {
|
if (!config_output.http.middlewares) {
|
||||||
config_output.http.middlewares = {};
|
config_output.http.middlewares = {};
|
||||||
}
|
}
|
||||||
config_output.http.middlewares[headersMiddlewareName] = {
|
config_output.http.middlewares[headersMiddlewareName] = {
|
||||||
headers: {
|
headers: {
|
||||||
customRequestHeaders: headersObj
|
...(hasRequestHeaders && { customRequestHeaders: requestHeadersObj }),
|
||||||
|
...(hasResponseHeaders && { customResponseHeaders: responseHeadersObj })
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -105,9 +105,12 @@ export async function getResource(
|
|||||||
return response<GetResourceResponse>(res, {
|
return response<GetResourceResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
...resource,
|
...resource,
|
||||||
headers: resource.headers
|
requestHeaders: resource.requestHeaders
|
||||||
? JSON.parse(resource.headers)
|
? JSON.parse(resource.requestHeaders)
|
||||||
: resource.headers
|
: resource.requestHeaders,
|
||||||
|
responseHeaders: resource.responseHeaders
|
||||||
|
? JSON.parse(resource.responseHeaders)
|
||||||
|
: resource.responseHeaders
|
||||||
},
|
},
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
|
|||||||
@@ -58,7 +58,11 @@ const updateHttpResourceBodySchema = z
|
|||||||
tlsServerName: z.string().nullable().optional(),
|
tlsServerName: z.string().nullable().optional(),
|
||||||
setHostHeader: z.string().nullable().optional(),
|
setHostHeader: z.string().nullable().optional(),
|
||||||
skipToIdpId: z.int().positive().nullable().optional(),
|
skipToIdpId: z.int().positive().nullable().optional(),
|
||||||
headers: z
|
requestHeaders: z
|
||||||
|
.array(z.strictObject({ name: z.string(), value: z.string() }))
|
||||||
|
.nullable()
|
||||||
|
.optional(),
|
||||||
|
responseHeaders: z
|
||||||
.array(z.strictObject({ name: z.string(), value: z.string() }))
|
.array(z.strictObject({ name: z.string(), value: z.string() }))
|
||||||
.nullable()
|
.nullable()
|
||||||
.optional(),
|
.optional(),
|
||||||
@@ -111,12 +115,12 @@ const updateHttpResourceBodySchema = z
|
|||||||
)
|
)
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
if (data.headers) {
|
const validHeaderName = /^[a-zA-Z0-9!#$%&'*+\-.^_`|~]+$/;
|
||||||
// HTTP header names must be valid token characters (RFC 7230)
|
const allHeaders = [
|
||||||
const validHeaderName = /^[a-zA-Z0-9!#$%&'*+\-.^_`|~]+$/;
|
...(data.requestHeaders ?? []),
|
||||||
return data.headers.every((h) => validHeaderName.test(h.name));
|
...(data.responseHeaders ?? [])
|
||||||
}
|
];
|
||||||
return true;
|
return allHeaders.every((h) => validHeaderName.test(h.name));
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
error: "Header names may only contain valid HTTP token characters (letters, digits, and !#$%&'*+-.^_`|~)."
|
error: "Header names may only contain valid HTTP token characters (letters, digits, and !#$%&'*+-.^_`|~)."
|
||||||
@@ -124,14 +128,12 @@ const updateHttpResourceBodySchema = z
|
|||||||
)
|
)
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
if (data.headers) {
|
const validHeaderValue = /^[\t\x20-\x7E]*$/;
|
||||||
// HTTP header values must be visible ASCII or horizontal whitespace, no control chars (RFC 7230)
|
const allHeaders = [
|
||||||
const validHeaderValue = /^[\t\x20-\x7E]*$/;
|
...(data.requestHeaders ?? []),
|
||||||
return data.headers.every((h) =>
|
...(data.responseHeaders ?? [])
|
||||||
validHeaderValue.test(h.value)
|
];
|
||||||
);
|
return allHeaders.every((h) => validHeaderValue.test(h.value));
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
error: "Header values may only contain printable ASCII characters and horizontal whitespace."
|
error: "Header values may only contain printable ASCII characters and horizontal whitespace."
|
||||||
@@ -139,16 +141,16 @@ const updateHttpResourceBodySchema = z
|
|||||||
)
|
)
|
||||||
.refine(
|
.refine(
|
||||||
(data) => {
|
(data) => {
|
||||||
if (data.headers) {
|
const templatePattern = /\{\{[^}]+\}\}/;
|
||||||
// Reject Traefik template syntax {{word}} in names or values
|
const allHeaders = [
|
||||||
const templatePattern = /\{\{[^}]+\}\}/;
|
...(data.requestHeaders ?? []),
|
||||||
return data.headers.every(
|
...(data.responseHeaders ?? [])
|
||||||
(h) =>
|
];
|
||||||
!templatePattern.test(h.name) &&
|
return allHeaders.every(
|
||||||
!templatePattern.test(h.value)
|
(h) =>
|
||||||
);
|
!templatePattern.test(h.name) &&
|
||||||
}
|
!templatePattern.test(h.value)
|
||||||
return true;
|
);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
error: "Header names and values must not contain template expressions such as {{value}}."
|
error: "Header names and values must not contain template expressions such as {{value}}."
|
||||||
@@ -467,11 +469,18 @@ async function updateHttpResource(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let headers = undefined;
|
let requestHeaders = undefined;
|
||||||
if (updateData.headers) {
|
if (updateData.requestHeaders) {
|
||||||
headers = JSON.stringify(updateData.headers);
|
requestHeaders = JSON.stringify(updateData.requestHeaders);
|
||||||
} else if (updateData.headers === null) {
|
} else if (updateData.requestHeaders === null) {
|
||||||
headers = null;
|
requestHeaders = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let responseHeaders = undefined;
|
||||||
|
if (updateData.responseHeaders) {
|
||||||
|
responseHeaders = JSON.stringify(updateData.responseHeaders);
|
||||||
|
} else if (updateData.responseHeaders === null) {
|
||||||
|
responseHeaders = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLicensed = await isLicensedOrSubscribed(
|
const isLicensed = await isLicensedOrSubscribed(
|
||||||
@@ -488,7 +497,7 @@ async function updateHttpResource(
|
|||||||
|
|
||||||
const updatedResource = await db
|
const updatedResource = await db
|
||||||
.update(resources)
|
.update(resources)
|
||||||
.set({ ...updateData, headers })
|
.set({ ...updateData, requestHeaders, responseHeaders })
|
||||||
.where(eq(resources.resourceId, resource.resourceId))
|
.where(eq(resources.resourceId, resource.resourceId))
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import m16 from "./scriptsPg/1.17.0";
|
|||||||
import m17 from "./scriptsPg/1.18.0";
|
import m17 from "./scriptsPg/1.18.0";
|
||||||
import m18 from "./scriptsPg/1.18.3";
|
import m18 from "./scriptsPg/1.18.3";
|
||||||
import m19 from "./scriptsPg/1.18.4";
|
import m19 from "./scriptsPg/1.18.4";
|
||||||
|
import m20 from "./scriptsPg/1.18.5";
|
||||||
|
|
||||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||||
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
||||||
@@ -49,7 +50,8 @@ const migrations = [
|
|||||||
{ version: "1.17.0", run: m16 },
|
{ version: "1.17.0", run: m16 },
|
||||||
{ version: "1.18.0", run: m17 },
|
{ version: "1.18.0", run: m17 },
|
||||||
{ version: "1.18.3", run: m18 },
|
{ version: "1.18.3", run: m18 },
|
||||||
{ version: "1.18.4", run: m19 }
|
{ version: "1.18.4", run: m19 },
|
||||||
|
{ version: "1.18.5", run: m20 }
|
||||||
// Add new migrations here as they are created
|
// Add new migrations here as they are created
|
||||||
] as {
|
] as {
|
||||||
version: string;
|
version: string;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import m37 from "./scriptsSqlite/1.17.0";
|
|||||||
import m38 from "./scriptsSqlite/1.18.0";
|
import m38 from "./scriptsSqlite/1.18.0";
|
||||||
import m39 from "./scriptsSqlite/1.18.3";
|
import m39 from "./scriptsSqlite/1.18.3";
|
||||||
import m40 from "./scriptsSqlite/1.18.4";
|
import m40 from "./scriptsSqlite/1.18.4";
|
||||||
|
import m41 from "./scriptsSqlite/1.18.5";
|
||||||
|
|
||||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||||
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
||||||
@@ -83,7 +84,8 @@ const migrations = [
|
|||||||
{ version: "1.17.0", run: m37 },
|
{ version: "1.17.0", run: m37 },
|
||||||
{ version: "1.18.0", run: m38 },
|
{ version: "1.18.0", run: m38 },
|
||||||
{ version: "1.18.3", run: m39 },
|
{ version: "1.18.3", run: m39 },
|
||||||
{ version: "1.18.4", run: m40 }
|
{ version: "1.18.4", run: m40 },
|
||||||
|
{ version: "1.18.5", run: m41 }
|
||||||
// Add new migrations here as they are created
|
// Add new migrations here as they are created
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { db } from "@server/db/pg/driver";
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
|
|
||||||
|
const version = "1.18.5";
|
||||||
|
|
||||||
|
export default async function migration() {
|
||||||
|
console.log(`Running setup script ${version}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.execute(sql`BEGIN`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "resources" RENAME COLUMN "headers" TO "requestHeaders";
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
ALTER TABLE "resources" ADD COLUMN "responseHeaders" text;
|
||||||
|
`);
|
||||||
|
|
||||||
|
await db.execute(sql`COMMIT`);
|
||||||
|
console.log("Migrated database");
|
||||||
|
} catch (e) {
|
||||||
|
await db.execute(sql`ROLLBACK`);
|
||||||
|
console.log("Unable to migrate database");
|
||||||
|
console.log(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${version} migration complete`);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { APP_PATH } from "@server/lib/consts";
|
||||||
|
import Database from "better-sqlite3";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const version = "1.18.5";
|
||||||
|
|
||||||
|
export default async function migration() {
|
||||||
|
console.log(`Running setup script ${version}...`);
|
||||||
|
|
||||||
|
const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||||
|
const db = new Database(location);
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.pragma("foreign_keys = OFF");
|
||||||
|
|
||||||
|
db.transaction(() => {
|
||||||
|
db.prepare(
|
||||||
|
`ALTER TABLE 'resources' RENAME COLUMN 'headers' TO 'requestHeaders';`
|
||||||
|
).run();
|
||||||
|
db.prepare(
|
||||||
|
`ALTER TABLE 'resources' ADD 'responseHeaders' text;`
|
||||||
|
).run();
|
||||||
|
})();
|
||||||
|
|
||||||
|
db.pragma("foreign_keys = ON");
|
||||||
|
|
||||||
|
console.log("Migrated database");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Failed to migrate db:", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${version} migration complete`);
|
||||||
|
}
|
||||||
@@ -1097,7 +1097,10 @@ function ProxyResourceHttpForm({
|
|||||||
message: t("proxyErrorInvalidHeader")
|
message: t("proxyErrorInvalidHeader")
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
headers: z
|
requestHeaders: z
|
||||||
|
.array(z.object({ name: z.string(), value: z.string() }))
|
||||||
|
.nullable(),
|
||||||
|
responseHeaders: z
|
||||||
.array(z.object({ name: z.string(), value: z.string() }))
|
.array(z.object({ name: z.string(), value: z.string() }))
|
||||||
.nullable(),
|
.nullable(),
|
||||||
proxyProtocol: z.boolean().optional(),
|
proxyProtocol: z.boolean().optional(),
|
||||||
@@ -1108,7 +1111,8 @@ function ProxyResourceHttpForm({
|
|||||||
resolver: zodResolver(proxySettingsSchema),
|
resolver: zodResolver(proxySettingsSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
setHostHeader: resource.setHostHeader || "",
|
setHostHeader: resource.setHostHeader || "",
|
||||||
headers: resource.headers,
|
requestHeaders: resource.requestHeaders,
|
||||||
|
responseHeaders: resource.responseHeaders,
|
||||||
proxyProtocol: resource.proxyProtocol || false,
|
proxyProtocol: resource.proxyProtocol || false,
|
||||||
proxyProtocolVersion: resource.proxyProtocolVersion || 1
|
proxyProtocolVersion: resource.proxyProtocolVersion || 1
|
||||||
}
|
}
|
||||||
@@ -1148,7 +1152,8 @@ function ProxyResourceHttpForm({
|
|||||||
ssl: tlsData.ssl,
|
ssl: tlsData.ssl,
|
||||||
tlsServerName: tlsData.tlsServerName || null,
|
tlsServerName: tlsData.tlsServerName || null,
|
||||||
setHostHeader: proxyData.setHostHeader || null,
|
setHostHeader: proxyData.setHostHeader || null,
|
||||||
headers: proxyData.headers || null
|
requestHeaders: proxyData.requestHeaders || null,
|
||||||
|
responseHeaders: proxyData.responseHeaders || null
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single API call to update all settings
|
// Single API call to update all settings
|
||||||
@@ -1161,7 +1166,8 @@ function ProxyResourceHttpForm({
|
|||||||
ssl: tlsData.ssl,
|
ssl: tlsData.ssl,
|
||||||
tlsServerName: tlsData.tlsServerName || null,
|
tlsServerName: tlsData.tlsServerName || null,
|
||||||
setHostHeader: proxyData.setHostHeader || null,
|
setHostHeader: proxyData.setHostHeader || null,
|
||||||
headers: proxyData.headers || null
|
requestHeaders: proxyData.requestHeaders || null,
|
||||||
|
responseHeaders: proxyData.responseHeaders || null
|
||||||
});
|
});
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
@@ -1307,11 +1313,11 @@ function ProxyResourceHttpForm({
|
|||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={proxySettingsForm.control}
|
control={proxySettingsForm.control}
|
||||||
name="headers"
|
name="requestHeaders"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("customHeaders")}
|
{t("customRequestHeaders")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<HeadersInput
|
<HeadersInput
|
||||||
@@ -1323,7 +1329,31 @@ function ProxyResourceHttpForm({
|
|||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t("customHeadersDescription")}
|
{t("customRequestHeadersDescription")}
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={proxySettingsForm.control}
|
||||||
|
name="responseHeaders"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
{t("customResponseHeaders")}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<HeadersInput
|
||||||
|
value={field.value}
|
||||||
|
onChange={(value) => {
|
||||||
|
field.onChange(value);
|
||||||
|
}}
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
{t("customResponseHeadersDescription")}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@@ -1369,7 +1399,7 @@ function ProxyResourceProtocolForm({
|
|||||||
message: t("proxyErrorInvalidHeader")
|
message: t("proxyErrorInvalidHeader")
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
headers: z
|
requestHeaders: z
|
||||||
.array(z.object({ name: z.string(), value: z.string() }))
|
.array(z.object({ name: z.string(), value: z.string() }))
|
||||||
.nullable(),
|
.nullable(),
|
||||||
proxyProtocol: z.boolean().optional(),
|
proxyProtocol: z.boolean().optional(),
|
||||||
@@ -1380,7 +1410,7 @@ function ProxyResourceProtocolForm({
|
|||||||
resolver: zodResolver(proxySettingsSchema),
|
resolver: zodResolver(proxySettingsSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
setHostHeader: resource.setHostHeader || "",
|
setHostHeader: resource.setHostHeader || "",
|
||||||
headers: resource.headers,
|
requestHeaders: resource.requestHeaders,
|
||||||
proxyProtocol: resource.proxyProtocol || false,
|
proxyProtocol: resource.proxyProtocol || false,
|
||||||
proxyProtocolVersion: resource.proxyProtocolVersion || 1
|
proxyProtocolVersion: resource.proxyProtocolVersion || 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1317,7 +1317,7 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t(
|
{t(
|
||||||
"customHeaders"
|
"customRequestHeaders"
|
||||||
)}
|
)}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
@@ -1341,7 +1341,7 @@ export function HealthCheckCredenza(props: HealthCheckCredenzaProps) {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t(
|
{t(
|
||||||
"customHeadersDescription"
|
"customRequestHeadersDescription"
|
||||||
)}
|
)}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ export function HealthCheckFormFields({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("customHeaders")}
|
{t("customRequestHeaders")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<HeadersInput
|
<HeadersInput
|
||||||
@@ -750,7 +750,7 @@ export function HealthCheckFormFields({
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t(
|
{t(
|
||||||
"customHeadersDescription"
|
"customRequestHeadersDescription"
|
||||||
)}
|
)}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
|||||||
Reference in New Issue
Block a user