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