diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 50c615b7bd..d54e941d2e 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -630,7 +630,7 @@ const internalCertificate = { * @param {String} privateKey This is the entire key contents as a string */ checkPrivateKey: async (privateKey) => { - const filepath = await tempWrite(privateKey, "/tmp"); + const filepath = await tempWrite(privateKey); const failTimeout = setTimeout(() => { throw new error.ValidationError( "Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.", @@ -660,7 +660,7 @@ const internalCertificate = { * @param {Boolean} [throwExpired] Throw when the certificate is out of date */ getCertificateInfo: async (certificate, throwExpired) => { - const filepath = await tempWrite(certificate, "/tmp"); + const filepath = await tempWrite(certificate); try { const certData = await internalCertificate.getCertificateInfoFromFile(filepath, throwExpired); fs.unlinkSync(filepath); diff --git a/backend/internal/host.js b/backend/internal/host.js index 748716262a..9f4fa201a7 100644 --- a/backend/internal/host.js +++ b/backend/internal/host.js @@ -20,6 +20,7 @@ const internalHost = { if (!combinedData.certificate_id) { combinedData.ssl_forced = false; combinedData.http2_support = false; + combinedData.http3_support = false; } if (!combinedData.ssl_forced) { diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index fe84607f96..d16121c861 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -2,6 +2,7 @@ import fs from "node:fs"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import _ from "lodash"; +import db from "../db.js"; import errs from "../lib/error.js"; import utils from "../lib/utils.js"; import { debug, nginx as logger } from "../logger.js"; @@ -9,6 +10,8 @@ import { debug, nginx as logger } from "../logger.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); +const HTTP_HOST_TABLES = ["proxy_host", "redirection_host", "dead_host"]; + const internalNginx = { /** * This will: @@ -158,6 +161,7 @@ const internalNginx = { { block_exploits: host.block_exploits }, { allow_websocket_upgrade: host.allow_websocket_upgrade }, { http2_support: host.http2_support }, + { http3_support: host.http3_support }, { hsts_enabled: host.hsts_enabled }, { hsts_subdomains: host.hsts_subdomains }, { access_list: host.access_list }, @@ -241,7 +245,16 @@ const internalNginx = { // Set the IPv6 setting for the host host.ipv6 = internalNginx.ipv6Enabled(); - locationsPromise.then(() => { + locationsPromise + .then(async () => { + const friendlyHostType = internalNginx.getFileFriendlyHostType(host_type); + if (HTTP_HOST_TABLES.includes(friendlyHostType) && (host.http3_support === 1 || host.http3_support === true)) { + host.http3_first = await internalNginx.isFirstHttp3Host(friendlyHostType, host.id); + } else { + host.http3_first = false; + } + }) + .then(() => { renderEngine .parseAndRender(template, host) .then((config_text) => { @@ -257,10 +270,38 @@ const internalNginx = { debug(logger, `Could not write ${filename}:`, err.message); reject(new errs.ConfigurationError(err.message)); }); - }); + }) + .catch((err) => { + reject(new errs.ConfigurationError(err.message)); + }); }); }, + /** + * @param {String} hostType + * @param {Number} hostId + * @returns {Promise} + */ + isFirstHttp3Host: async (hostType, hostId) => { + const knex = db(); + const rows = await Promise.all( + HTTP_HOST_TABLES.map((table) => + knex(table) + .select("id") + .where("is_deleted", 0) + .andWhere("enabled", 1) + .andWhere("http3_support", 1) + .andWhere("certificate_id", ">", 0), + ), + ); + + const all = rows + .flatMap((tableRows, index) => tableRows.map((row) => ({ host_type: HTTP_HOST_TABLES[index], id: row.id }))) + .sort((a, b) => (a.id === b.id ? a.host_type.localeCompare(b.host_type) : a.id - b.id)); + + return all.length > 0 && all[0].host_type === hostType && all[0].id === hostId; + }, + /** * This generates a temporary nginx config listening on port 80 for the domain names listed * in the certificate setup. It allows the letsencrypt acme challenge to be requested by letsencrypt diff --git a/backend/migrations/20251112090000_http3_support.js b/backend/migrations/20251112090000_http3_support.js new file mode 100644 index 0000000000..2976cb8df9 --- /dev/null +++ b/backend/migrations/20251112090000_http3_support.js @@ -0,0 +1,50 @@ +import { migrate as logger } from "../logger.js"; + +const migrateName = "http3_support"; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @returns {Promise} + */ +const up = (knex) => { + logger.info(`[${migrateName}] Migrating Up...`); + + return knex.schema + .table("proxy_host", (proxy_host) => { + proxy_host.integer("http3_support").notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info(`[${migrateName}] proxy_host Table altered`); + + return knex.schema.table("redirection_host", (redirection_host) => { + redirection_host.integer("http3_support").notNull().unsigned().defaultTo(0); + }); + }) + .then(() => { + logger.info(`[${migrateName}] redirection_host Table altered`); + + return knex.schema.table("dead_host", (dead_host) => { + dead_host.integer("http3_support").notNull().unsigned().defaultTo(0); + }); + }) + .then(() => { + logger.info(`[${migrateName}] dead_host Table altered`); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @returns {Promise} + */ +const down = (_knex) => { + logger.warn(`[${migrateName}] You can't migrate down this one.`); + return Promise.resolve(true); +}; + +export { up, down }; diff --git a/backend/models/dead_host.js b/backend/models/dead_host.js index 0acf7ca76a..26c16ee2ea 100644 --- a/backend/models/dead_host.js +++ b/backend/models/dead_host.js @@ -10,7 +10,7 @@ import User from "./user.js"; Model.knex(db()); -const boolFields = ["is_deleted", "ssl_forced", "http2_support", "enabled", "hsts_enabled", "hsts_subdomains"]; +const boolFields = ["is_deleted", "ssl_forced", "http2_support", "http3_support", "enabled", "hsts_enabled", "hsts_subdomains"]; class DeadHost extends Model { $beforeInsert() { diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js index e8f447c8e7..71f49710a8 100644 --- a/backend/models/proxy_host.js +++ b/backend/models/proxy_host.js @@ -18,6 +18,7 @@ const boolFields = [ "block_exploits", "allow_websocket_upgrade", "http2_support", + "http3_support", "enabled", "hsts_enabled", "hsts_subdomains", diff --git a/backend/models/redirection_host.js b/backend/models/redirection_host.js index 46c7301754..d7e693d03a 100644 --- a/backend/models/redirection_host.js +++ b/backend/models/redirection_host.js @@ -19,6 +19,7 @@ const boolFields = [ "hsts_enabled", "hsts_subdomains", "http2_support", + "http3_support", ]; class RedirectionHost extends Model { diff --git a/backend/schema/common.json b/backend/schema/common.json index 00b06e005f..e7ec37e8b7 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -118,6 +118,11 @@ "type": "boolean", "example": true }, + "http3_support": { + "description": "HTTP3 Protocol Support", + "type": "boolean", + "example": true + }, "block_exploits": { "description": "Should we block common exploits", "type": "boolean", diff --git a/backend/schema/components/dead-host-object.json b/backend/schema/components/dead-host-object.json index b876ebf0a8..ccc941ac5f 100644 --- a/backend/schema/components/dead-host-object.json +++ b/backend/schema/components/dead-host-object.json @@ -1,7 +1,22 @@ { "type": "object", "description": "404 Host object", - "required": ["id", "created_on", "modified_on", "owner_user_id", "domain_names", "certificate_id", "ssl_forced", "hsts_enabled", "hsts_subdomains", "http2_support", "advanced_config", "enabled", "meta"], + "required": [ + "id", + "created_on", + "modified_on", + "owner_user_id", + "domain_names", + "certificate_id", + "ssl_forced", + "hsts_enabled", + "hsts_subdomains", + "http2_support", + "http3_support", + "advanced_config", + "enabled", + "meta" + ], "additionalProperties": false, "properties": { "id": { @@ -34,6 +49,9 @@ "http2_support": { "$ref": "../common.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../common.json#/properties/http3_support" + }, "advanced_config": { "type": "string", "example": "" diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json index 3ac6462136..1e67b4be3c 100644 --- a/backend/schema/components/proxy-host-object.json +++ b/backend/schema/components/proxy-host-object.json @@ -18,6 +18,7 @@ "meta", "allow_websocket_upgrade", "http2_support", + "http3_support", "forward_scheme", "enabled", "locations", @@ -87,6 +88,9 @@ "http2_support": { "$ref": "../common.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../common.json#/properties/http3_support" + }, "forward_scheme": { "type": "string", "enum": ["http", "https"], diff --git a/backend/schema/components/redirection-host-object.json b/backend/schema/components/redirection-host-object.json index 58169720b6..5a1b17aa31 100644 --- a/backend/schema/components/redirection-host-object.json +++ b/backend/schema/components/redirection-host-object.json @@ -16,6 +16,7 @@ "hsts_enabled", "hsts_subdomains", "http2_support", + "http3_support", "block_exploits", "advanced_config", "enabled", @@ -80,6 +81,9 @@ "http2_support": { "$ref": "../common.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../common.json#/properties/http3_support" + }, "block_exploits": { "$ref": "../common.json#/properties/block_exploits" }, diff --git a/backend/schema/paths/nginx/dead-hosts/get.json b/backend/schema/paths/nginx/dead-hosts/get.json index feb04ff227..381e3357f8 100644 --- a/backend/schema/paths/nginx/dead-hosts/get.json +++ b/backend/schema/paths/nginx/dead-hosts/get.json @@ -40,6 +40,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/get.json b/backend/schema/paths/nginx/dead-hosts/hostID/get.json index a3c24edc34..3ea223b26f 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/get.json @@ -41,6 +41,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/put.json b/backend/schema/paths/nginx/dead-hosts/hostID/put.json index e07217c45c..5909e06896 100644 --- a/backend/schema/paths/nginx/dead-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/dead-hosts/hostID/put.json @@ -48,6 +48,9 @@ "http2_support": { "$ref": "../../../../components/dead-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../../components/dead-host-object.json#/properties/http3_support" + }, "advanced_config": { "$ref": "../../../../components/dead-host-object.json#/properties/advanced_config" }, @@ -80,6 +83,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/schema/paths/nginx/dead-hosts/post.json b/backend/schema/paths/nginx/dead-hosts/post.json index 1ec38720c8..b731a37e5a 100644 --- a/backend/schema/paths/nginx/dead-hosts/post.json +++ b/backend/schema/paths/nginx/dead-hosts/post.json @@ -39,6 +39,9 @@ "http2_support": { "$ref": "../../../components/dead-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../components/dead-host-object.json#/properties/http3_support" + }, "advanced_config": { "$ref": "../../../components/dead-host-object.json#/properties/advanced_config" }, @@ -55,6 +58,7 @@ "ssl_forced": false, "advanced_config": "", "http2_support": false, + "http3_support": false, "hsts_enabled": false, "hsts_subdomains": false, "meta": {} @@ -82,6 +86,7 @@ "advanced_config": "", "meta": {}, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/schema/paths/nginx/proxy-hosts/get.json b/backend/schema/paths/nginx/proxy-hosts/get.json index 301e28bfdf..adfc5a2585 100644 --- a/backend/schema/paths/nginx/proxy-hosts/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/get.json @@ -54,6 +54,7 @@ }, "allow_websocket_upgrade": false, "http2_support": false, + "http3_support": false, "forward_scheme": "http", "enabled": true, "locations": [], diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json index 2e677fed32..86887e674a 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json @@ -51,6 +51,7 @@ }, "allow_websocket_upgrade": false, "http2_support": false, + "http3_support": false, "forward_scheme": "http", "enabled": true, "locations": [], diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json index fc3198456b..251c759ad5 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json @@ -62,6 +62,9 @@ "http2_support": { "$ref": "../../../../components/proxy-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../../components/proxy-host-object.json#/properties/http3_support" + }, "block_exploits": { "$ref": "../../../../components/proxy-host-object.json#/properties/block_exploits" }, @@ -120,6 +123,7 @@ }, "allow_websocket_upgrade": false, "http2_support": false, + "http3_support": false, "forward_scheme": "http", "enabled": true, "locations": [], diff --git a/backend/schema/paths/nginx/proxy-hosts/post.json b/backend/schema/paths/nginx/proxy-hosts/post.json index 28ddad8fc2..52b221eb0b 100644 --- a/backend/schema/paths/nginx/proxy-hosts/post.json +++ b/backend/schema/paths/nginx/proxy-hosts/post.json @@ -54,6 +54,9 @@ "http2_support": { "$ref": "../../../components/proxy-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../components/proxy-host-object.json#/properties/http3_support" + }, "block_exploits": { "$ref": "../../../components/proxy-host-object.json#/properties/block_exploits" }, @@ -117,6 +120,7 @@ "meta": {}, "allow_websocket_upgrade": false, "http2_support": false, + "http3_support": false, "forward_scheme": "http", "enabled": true, "locations": [], diff --git a/backend/schema/paths/nginx/redirection-hosts/get.json b/backend/schema/paths/nginx/redirection-hosts/get.json index dfeb60497b..beeb182705 100644 --- a/backend/schema/paths/nginx/redirection-hosts/get.json +++ b/backend/schema/paths/nginx/redirection-hosts/get.json @@ -43,6 +43,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json index 577b5144a9..145e4d2adf 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json @@ -44,6 +44,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json index 454a38805e..66972ff1fb 100644 --- a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json @@ -60,6 +60,9 @@ "http2_support": { "$ref": "../../../../components/redirection-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../../components/redirection-host-object.json#/properties/http3_support" + }, "block_exploits": { "$ref": "../../../../components/redirection-host-object.json#/properties/block_exploits" }, @@ -98,6 +101,7 @@ "nginx_err": null }, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/schema/paths/nginx/redirection-hosts/post.json b/backend/schema/paths/nginx/redirection-hosts/post.json index 6aa533010e..befd9aafd3 100644 --- a/backend/schema/paths/nginx/redirection-hosts/post.json +++ b/backend/schema/paths/nginx/redirection-hosts/post.json @@ -54,6 +54,9 @@ "http2_support": { "$ref": "../../../components/redirection-host-object.json#/properties/http2_support" }, + "http3_support": { + "$ref": "../../../components/redirection-host-object.json#/properties/http3_support" + }, "block_exploits": { "$ref": "../../../components/redirection-host-object.json#/properties/block_exploits" }, @@ -77,6 +80,7 @@ "certificate_id": 0, "ssl_forced": false, "http2_support": false, + "http3_support": false, "hsts_enabled": false, "hsts_subdomains": false, "advanced_config": "", @@ -108,6 +112,7 @@ "advanced_config": "", "meta": {}, "http2_support": false, + "http3_support": false, "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 34a808e6a0..889fb2aa7c 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -11,10 +11,33 @@ {% else -%} #listen [::]:443; {% endif %} +{% if http3_support == 1 or http3_support == true %} +{% if http3_first == 1 or http3_first == true %} + listen 443 quic reuseport; +{% if ipv6 -%} + listen [::]:443 quic reuseport; +{% else -%} + #listen [::]:443 quic reuseport; +{% endif %} +{% else -%} + listen 443 quic; +{% if ipv6 -%} + listen [::]:443 quic; +{% else -%} + #listen [::]:443 quic; +{% endif %} +{% endif %} + add_header Alt-Svc 'h3=":443"; ma=86400' always; +{% endif %} {% endif %} server_name {{ domain_names | join: " " }}; {% if http2_support == 1 or http2_support == true %} http2 on; {% else -%} http2 off; -{% endif %} \ No newline at end of file +{% endif %} +{% if http3_support == 1 or http3_support == true %} + http3 on; +{% else -%} + http3 off; +{% endif %} diff --git a/docker/rootfs/etc/nginx/conf.d/default.conf b/docker/rootfs/etc/nginx/conf.d/default.conf index b3f61ebcb8..92d67d960f 100644 --- a/docker/rootfs/etc/nginx/conf.d/default.conf +++ b/docker/rootfs/etc/nginx/conf.d/default.conf @@ -22,8 +22,8 @@ server { # First 443 Host, which is the default if another default doesn't exist server { - listen 443 ssl; - listen [::]:443 ssl; + listen 443 ssl reuseport; + listen [::]:443 ssl reuseport; set $forward_scheme "https"; set $server "127.0.0.1"; diff --git a/docker/rootfs/etc/nginx/nginx.conf b/docker/rootfs/etc/nginx/nginx.conf index 892cf158f5..932ffe64fd 100644 --- a/docker/rootfs/etc/nginx/nginx.conf +++ b/docker/rootfs/etc/nginx/nginx.conf @@ -39,6 +39,9 @@ http { client_max_body_size 2000m; server_names_hash_bucket_size 1024; proxy_http_version 1.1; + quic_retry on; + quic_gso on; + http3_stream_buffer_size 64k; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Accept-Encoding ""; diff --git a/frontend/package.json b/frontend/package.json index 6a573f3347..0c164f52a6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,11 +18,11 @@ "dependencies": { "@tabler/core": "^1.4.0", "@tabler/icons-react": "^3.36.1", - "@tanstack/react-query": "^5.90.20", + "@tanstack/react-query": "^5.90.21", "@tanstack/react-table": "^8.21.3", "@uiw/react-textarea-code-editor": "^3.1.1", "classnames": "^2.5.1", - "country-flag-icons": "^1.6.12", + "country-flag-icons": "^1.6.13", "date-fns": "^4.1.0", "ez-modal-react": "^1.0.5", "formik": "^2.4.9", @@ -40,7 +40,7 @@ "rooks": "^9.5.0" }, "devDependencies": { - "@biomejs/biome": "^2.3.14", + "@biomejs/biome": "^2.4.2", "@formatjs/cli": "^6.12.2", "@tanstack/react-query-devtools": "^5.91.3", "@testing-library/dom": "^10.4.1", @@ -52,7 +52,7 @@ "@types/react-dom": "^19.2.3", "@types/react-table": "^7.7.20", "@vitejs/plugin-react": "^5.1.4", - "happy-dom": "^20.5.3", + "happy-dom": "^20.6.1", "postcss": "^8.5.6", "postcss-simple-vars": "^7.0.1", "sass": "^1.97.3", diff --git a/frontend/src/api/backend/models.ts b/frontend/src/api/backend/models.ts index 2ae0b08348..f90683d3fe 100644 --- a/frontend/src/api/backend/models.ts +++ b/frontend/src/api/backend/models.ts @@ -123,6 +123,7 @@ export interface ProxyHost { meta: Record; allowWebsocketUpgrade: boolean; http2Support: boolean; + http3Support: boolean; enabled: boolean; locations?: ProxyLocation[]; hstsEnabled: boolean; @@ -145,6 +146,7 @@ export interface DeadHost { advancedConfig: string; meta: Record; http2Support: boolean; + http3Support: boolean; enabled: boolean; hstsEnabled: boolean; hstsSubdomains: boolean; @@ -167,6 +169,7 @@ export interface RedirectionHost { advancedConfig: string; meta: Record; http2Support: boolean; + http3Support: boolean; forwardScheme: string; forwardHttpCode: number; enabled: boolean; diff --git a/frontend/src/components/Form/SSLCertificateField.tsx b/frontend/src/components/Form/SSLCertificateField.tsx index 6ab3ea92c1..cd4ea08a05 100644 --- a/frontend/src/components/Form/SSLCertificateField.tsx +++ b/frontend/src/components/Form/SSLCertificateField.tsx @@ -32,7 +32,7 @@ interface Props { label?: string; required?: boolean; allowNew?: boolean; - forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields + forHttp?: boolean; // the sslForced, http2Support, http3Support, hstsEnabled, hstsSubdomains fields } export function SSLCertificateField({ name = "certificateId", @@ -52,6 +52,7 @@ export function SSLCertificateField({ const { sslForced, http2Support, + http3Support, hstsEnabled, hstsSubdomains, dnsChallenge, @@ -62,6 +63,7 @@ export function SSLCertificateField({ if (forHttp && !newValue?.value) { sslForced && setFieldValue("sslForced", false); http2Support && setFieldValue("http2Support", false); + http3Support && setFieldValue("http3Support", false); hstsEnabled && setFieldValue("hstsEnabled", false); hstsSubdomains && setFieldValue("hstsSubdomains", false); } diff --git a/frontend/src/components/Form/SSLOptionsFields.tsx b/frontend/src/components/Form/SSLOptionsFields.tsx index ecf23d26f1..a48d500806 100644 --- a/frontend/src/components/Form/SSLOptionsFields.tsx +++ b/frontend/src/components/Form/SSLOptionsFields.tsx @@ -4,7 +4,7 @@ import { DNSProviderFields, DomainNamesField } from "src/components"; import { T } from "src/locale"; interface Props { - forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields + forHttp?: boolean; // the sslForced, http2Support, http3Support, hstsEnabled, hstsSubdomains fields forProxyHost?: boolean; // the advanced fields forceDNSForNew?: boolean; requireDomainNames?: boolean; // used for streams @@ -16,7 +16,7 @@ export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDN const newCertificate = v?.certificateId === "new"; const hasCertificate = newCertificate || (v?.certificateId && v?.certificateId > 0); - const { sslForced, http2Support, hstsEnabled, hstsSubdomains, trustForwardedProto, meta } = v; + const { sslForced, http2Support, http3Support, hstsEnabled, hstsSubdomains, trustForwardedProto, meta } = v; const { dnsChallenge } = meta || {}; if (forceDNSForNew && newCertificate && !dnsChallenge) { @@ -38,7 +38,7 @@ export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDN const getHttpOptions = () => (
-
+
{({ field }: any) => (
-
+
+
+
{({ field }: any) => (
+
+ + {({ field }: any) => ( + + )} + +
diff --git a/frontend/src/hooks/useDeadHost.ts b/frontend/src/hooks/useDeadHost.ts index dd8355e3aa..be26b17793 100644 --- a/frontend/src/hooks/useDeadHost.ts +++ b/frontend/src/hooks/useDeadHost.ts @@ -14,6 +14,7 @@ const fetchDeadHost = (id: number | "new") => { advancedConfig: "", meta: {}, http2Support: false, + http3Support: false, enabled: true, hstsEnabled: false, hstsSubdomains: false, diff --git a/frontend/src/hooks/useProxyHost.ts b/frontend/src/hooks/useProxyHost.ts index 24e7f4fae2..27a1aead63 100644 --- a/frontend/src/hooks/useProxyHost.ts +++ b/frontend/src/hooks/useProxyHost.ts @@ -20,6 +20,7 @@ const fetchProxyHost = (id: number | "new") => { meta: {}, allowWebsocketUpgrade: false, http2Support: false, + http3Support: false, forwardScheme: "", enabled: true, hstsEnabled: false, diff --git a/frontend/src/hooks/useRedirectionHost.ts b/frontend/src/hooks/useRedirectionHost.ts index ff2126538d..965f56f1e9 100644 --- a/frontend/src/hooks/useRedirectionHost.ts +++ b/frontend/src/hooks/useRedirectionHost.ts @@ -21,6 +21,7 @@ const fetchRedirectionHost = (id: number | "new") => { advancedConfig: "", meta: {}, http2Support: false, + http3Support: false, forwardScheme: "auto", forwardHttpCode: 301, blockExploits: false, diff --git a/frontend/src/locale/src/bg.json b/frontend/src/locale/src/bg.json index 5183fe315b..166cce5510 100644 --- a/frontend/src/locale/src/bg.json +++ b/frontend/src/locale/src/bg.json @@ -302,6 +302,9 @@ "domains.http2-support": { "defaultMessage": "Поддръжка на HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Поддръжка на HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Използване на DNS Challenge" }, diff --git a/frontend/src/locale/src/de.json b/frontend/src/locale/src/de.json index f654e10858..409a2fb852 100644 --- a/frontend/src/locale/src/de.json +++ b/frontend/src/locale/src/de.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Support" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 Support" + }, "domains.use-dns": { "defaultMessage": "Nutze DNS Challenge" }, diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json index bb00ac3322..929da1916d 100644 --- a/frontend/src/locale/src/en.json +++ b/frontend/src/locale/src/en.json @@ -362,6 +362,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Support" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 Support" + }, "domains.trust-forwarded-proto": { "defaultMessage": "Trust Upstream Forwarded Proto Headers" }, diff --git a/frontend/src/locale/src/es.json b/frontend/src/locale/src/es.json index c8b1edb075..0b90123fa6 100644 --- a/frontend/src/locale/src/es.json +++ b/frontend/src/locale/src/es.json @@ -302,6 +302,9 @@ "domains.http2-support": { "defaultMessage": "Soporte HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Soporte HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Usar Desafío DNS" }, diff --git a/frontend/src/locale/src/fr.json b/frontend/src/locale/src/fr.json index c715c028a6..dc4097442b 100644 --- a/frontend/src/locale/src/fr.json +++ b/frontend/src/locale/src/fr.json @@ -275,6 +275,9 @@ "domains.http2-support": { "defaultMessage": "Prise en charge de HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Prise en charge de HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Utiliser le challenge DNS" }, diff --git a/frontend/src/locale/src/ga.json b/frontend/src/locale/src/ga.json index 719b863bf0..7126283a17 100644 --- a/frontend/src/locale/src/ga.json +++ b/frontend/src/locale/src/ga.json @@ -290,6 +290,9 @@ "domains.http2-support": { "defaultMessage": "Tacaíocht HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Tacaíocht HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Úsáid Dúshlán DNS" }, diff --git a/frontend/src/locale/src/hu.json b/frontend/src/locale/src/hu.json index 4caf058344..a335ef1109 100644 --- a/frontend/src/locale/src/hu.json +++ b/frontend/src/locale/src/hu.json @@ -359,6 +359,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 támogatás" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 támogatás" + }, "domains.use-dns": { "defaultMessage": "DNS Challenge használata" }, diff --git a/frontend/src/locale/src/id.json b/frontend/src/locale/src/id.json index cb498f0d88..9228c4a718 100644 --- a/frontend/src/locale/src/id.json +++ b/frontend/src/locale/src/id.json @@ -290,6 +290,9 @@ "domains.http2-support": { "defaultMessage": "Dukungan HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Dukungan HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Gunakan DNS Challenge" }, diff --git a/frontend/src/locale/src/it.json b/frontend/src/locale/src/it.json index 7e5ca77113..0214955681 100644 --- a/frontend/src/locale/src/it.json +++ b/frontend/src/locale/src/it.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "Supporto HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Supporto HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Usa Challenge DNS" }, diff --git a/frontend/src/locale/src/ja.json b/frontend/src/locale/src/ja.json index 438dc218d3..09e4dcd2c9 100644 --- a/frontend/src/locale/src/ja.json +++ b/frontend/src/locale/src/ja.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2サポート" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3サポート" + }, "domains.use-dns": { "defaultMessage": "DNSチャレンジを使用" }, diff --git a/frontend/src/locale/src/ko.json b/frontend/src/locale/src/ko.json index 9c0093591b..ba92fc7b78 100644 --- a/frontend/src/locale/src/ko.json +++ b/frontend/src/locale/src/ko.json @@ -302,6 +302,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 지원" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 지원" + }, "domains.use-dns": { "defaultMessage": "DNS 챌린지 사용" }, diff --git a/frontend/src/locale/src/nl.json b/frontend/src/locale/src/nl.json index 81c37054ba..b82333cecb 100644 --- a/frontend/src/locale/src/nl.json +++ b/frontend/src/locale/src/nl.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Ondersteuning" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 Ondersteuning" + }, "domains.use-dns": { "defaultMessage": "Gebruik DNS Challenge" }, diff --git a/frontend/src/locale/src/pl.json b/frontend/src/locale/src/pl.json index a5fb2ad0be..ba0df8339b 100644 --- a/frontend/src/locale/src/pl.json +++ b/frontend/src/locale/src/pl.json @@ -293,6 +293,9 @@ "domains.http2-support": { "defaultMessage": "Obsługa HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Obsługa HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Użyj wyzwania DNS" }, diff --git a/frontend/src/locale/src/pt.json b/frontend/src/locale/src/pt.json index 0a789f484e..70cf9401c8 100644 --- a/frontend/src/locale/src/pt.json +++ b/frontend/src/locale/src/pt.json @@ -290,6 +290,9 @@ "domains.http2-support": { "defaultMessage": "Suporte HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Suporte HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Utilizar DNS Challenge" }, diff --git a/frontend/src/locale/src/ru.json b/frontend/src/locale/src/ru.json index 44dff1294c..51cff4466d 100644 --- a/frontend/src/locale/src/ru.json +++ b/frontend/src/locale/src/ru.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "Поддержка HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Поддержка HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Проверка через DNS" }, diff --git a/frontend/src/locale/src/sk.json b/frontend/src/locale/src/sk.json index 8d48cf811e..a222f0a59c 100644 --- a/frontend/src/locale/src/sk.json +++ b/frontend/src/locale/src/sk.json @@ -359,6 +359,9 @@ "domains.http2-support": { "defaultMessage": "Podpora HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Podpora HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Použiť DNS výzvu" }, diff --git a/frontend/src/locale/src/tr.json b/frontend/src/locale/src/tr.json index 972fa895ec..7ecdfb6186 100644 --- a/frontend/src/locale/src/tr.json +++ b/frontend/src/locale/src/tr.json @@ -290,6 +290,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Desteği" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 Desteği" + }, "domains.use-dns": { "defaultMessage": "DNS Challenge Kullan" }, diff --git a/frontend/src/locale/src/vi.json b/frontend/src/locale/src/vi.json index 32d26d5590..882c745d87 100644 --- a/frontend/src/locale/src/vi.json +++ b/frontend/src/locale/src/vi.json @@ -287,6 +287,9 @@ "domains.http2-support": { "defaultMessage": "Hỗ trợ HTTP/2" }, + "domains.http3-support": { + "defaultMessage": "Hỗ trợ HTTP/3" + }, "domains.use-dns": { "defaultMessage": "Dùng thử thách DNS" }, diff --git a/frontend/src/locale/src/zh.json b/frontend/src/locale/src/zh.json index 72494bb64f..1462c97b9e 100644 --- a/frontend/src/locale/src/zh.json +++ b/frontend/src/locale/src/zh.json @@ -290,6 +290,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 支持" }, + "domains.http3-support": { + "defaultMessage": "HTTP/3 支持" + }, "domains.trust-forwarded-proto": { "defaultMessage": "信任上游代理传递的协议类型头" }, diff --git a/frontend/src/modals/DeadHostModal.tsx b/frontend/src/modals/DeadHostModal.tsx index c9dce9a1c4..1c978bd4c0 100644 --- a/frontend/src/modals/DeadHostModal.tsx +++ b/frontend/src/modals/DeadHostModal.tsx @@ -69,6 +69,7 @@ const DeadHostModal = EasyModal.create(({ id, visible, remove }: Props) => { sslForced: data?.sslForced, advancedConfig: data?.advancedConfig, http2Support: data?.http2Support, + http3Support: data?.http3Support, hstsEnabled: data?.hstsEnabled, hstsSubdomains: data?.hstsSubdomains, meta: data?.meta || {}, diff --git a/frontend/src/modals/ProxyHostModal.tsx b/frontend/src/modals/ProxyHostModal.tsx index 3227be51bb..622ca714af 100644 --- a/frontend/src/modals/ProxyHostModal.tsx +++ b/frontend/src/modals/ProxyHostModal.tsx @@ -86,6 +86,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => { certificateId: data?.certificateId || 0, sslForced: data?.sslForced || false, http2Support: data?.http2Support || false, + http3Support: data?.http3Support || false, hstsEnabled: data?.hstsEnabled || false, hstsSubdomains: data?.hstsSubdomains || false, trustForwardedProto: data?.trustForwardedProto || false, diff --git a/frontend/src/modals/RedirectionHostModal.tsx b/frontend/src/modals/RedirectionHostModal.tsx index 1bd7877f4f..d22c4d079a 100644 --- a/frontend/src/modals/RedirectionHostModal.tsx +++ b/frontend/src/modals/RedirectionHostModal.tsx @@ -77,6 +77,7 @@ const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) = certificateId: data?.certificateId || 0, sslForced: data?.sslForced || false, http2Support: data?.http2Support || false, + http3Support: data?.http3Support || false, hstsEnabled: data?.hstsEnabled || false, hstsSubdomains: data?.hstsSubdomains || false, // Advanced tab diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 859af7b7fb..1720bee524 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -235,59 +235,59 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" -"@biomejs/biome@^2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.3.14.tgz#b879cd5e0495334d4db7c49d6f3cc95b67d2909c" - integrity sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA== +"@biomejs/biome@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.4.2.tgz#91fea27398106f87fa81118577756d9e29fe8c74" + integrity sha512-vVE/FqLxNLbvYnFDYg3Xfrh1UdFhmPT5i+yPT9GE2nTUgI4rkqo5krw5wK19YHBd7aE7J6r91RRmb8RWwkjy6w== optionalDependencies: - "@biomejs/cli-darwin-arm64" "2.3.14" - "@biomejs/cli-darwin-x64" "2.3.14" - "@biomejs/cli-linux-arm64" "2.3.14" - "@biomejs/cli-linux-arm64-musl" "2.3.14" - "@biomejs/cli-linux-x64" "2.3.14" - "@biomejs/cli-linux-x64-musl" "2.3.14" - "@biomejs/cli-win32-arm64" "2.3.14" - "@biomejs/cli-win32-x64" "2.3.14" - -"@biomejs/cli-darwin-arm64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.14.tgz#da942618e1dc2d19322bc11d5dacfe7d7616a502" - integrity sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A== - -"@biomejs/cli-darwin-x64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.14.tgz#3ad06cce8ef6d2b935582011bd0cc3ca98a9554d" - integrity sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA== - -"@biomejs/cli-linux-arm64-musl@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.14.tgz#e92681273dc59ac57b75b72f1b64a67543e50f8c" - integrity sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg== - -"@biomejs/cli-linux-arm64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.14.tgz#bab43ee0a88ba15a6d59ec648a4b415d68d6eeb7" - integrity sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ== - -"@biomejs/cli-linux-x64-musl@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.14.tgz#ee90f7110dafdedf4644e0a27ac242975dcd88d3" - integrity sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ== - -"@biomejs/cli-linux-x64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.14.tgz#d152e61c6dc847836ebc741fb70fe305414aa7fe" - integrity sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA== - -"@biomejs/cli-win32-arm64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.14.tgz#2c59e84f3d172bada2a1df94d6cf7e511c244a4e" - integrity sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A== - -"@biomejs/cli-win32-x64@2.3.14": - version "2.3.14" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.14.tgz#44405162f255fe153a5ff99379510c058bf7a1e8" - integrity sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ== + "@biomejs/cli-darwin-arm64" "2.4.2" + "@biomejs/cli-darwin-x64" "2.4.2" + "@biomejs/cli-linux-arm64" "2.4.2" + "@biomejs/cli-linux-arm64-musl" "2.4.2" + "@biomejs/cli-linux-x64" "2.4.2" + "@biomejs/cli-linux-x64-musl" "2.4.2" + "@biomejs/cli-win32-arm64" "2.4.2" + "@biomejs/cli-win32-x64" "2.4.2" + +"@biomejs/cli-darwin-arm64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.2.tgz#a748ec0a0d8f4ea559b4a3834e8981500caaa5fa" + integrity sha512-3pEcKCP/1POKyaZZhXcxFl3+d9njmeAihZ17k8lL/1vk+6e0Cbf0yPzKItFiT+5Yh6TQA4uKvnlqe0oVZwRxCA== + +"@biomejs/cli-darwin-x64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.2.tgz#b825d247a7e582c00c9782524284bea2033a272c" + integrity sha512-P7hK1jLVny+0R9UwyGcECxO6sjETxfPyBm/1dmFjnDOHgdDPjPqozByunrwh4xPKld8sxOr5eAsSqal5uKgeBg== + +"@biomejs/cli-linux-arm64-musl@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.2.tgz#9a2d15f525928f06d21fbc0eaea2e332be3ed5d9" + integrity sha512-/x04YK9+7erw6tYEcJv9WXoBHcULI/wMOvNdAyE9S3JStZZ9yJyV67sWAI+90UHuDo/BDhq0d96LDqGlSVv7WA== + +"@biomejs/cli-linux-arm64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.2.tgz#0f7928a3253cdb10ebf5884db452d81d7a49ba30" + integrity sha512-DI3Mi7GT2zYNgUTDEbSjl3e1KhoP76OjQdm8JpvZYZWtVDRyLd3w8llSr2TWk1z+U3P44kUBWY3X7H9MD1/DGQ== + +"@biomejs/cli-linux-x64-musl@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.2.tgz#07c971451e62f6e147ec58b7acae345792d331b1" + integrity sha512-wbBmTkeAoAYbOQ33f6sfKG7pcRSydQiF+dTYOBjJsnXO2mWEOQHllKlC2YVnedqZFERp2WZhFUoO7TNRwnwEHQ== + +"@biomejs/cli-linux-x64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.2.tgz#0c7755fe8b5b2745d6afa8e14806591aefef52e3" + integrity sha512-GK2ErnrKpWFigYP68cXiCHK4RTL4IUWhK92AFS3U28X/nuAL5+hTuy6hyobc8JZRSt+upXt1nXChK+tuHHx4mA== + +"@biomejs/cli-win32-arm64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.2.tgz#a25007d0eb8ac4bbf81fb0fd010a68ce38fd46d1" + integrity sha512-k2uqwLYrNNxnaoiW3RJxoMGnbKda8FuCmtYG3cOtVljs3CzWxaTR+AoXwKGHscC9thax9R4kOrtWqWN0+KdPTw== + +"@biomejs/cli-win32-x64@2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.2.tgz#7693a47973bd1c910a7ce3d7eb8133292f779646" + integrity sha512-9ma7C4g8Sq3cBlRJD2yrsHXB1mnnEBdpy7PhvFrylQWQb4PoyCmPucdX7frvsSBQuFtIiKCrolPl/8tCZrKvgQ== "@emotion/babel-plugin@^11.13.5": version "11.13.5" @@ -908,10 +908,10 @@ dependencies: "@tanstack/query-devtools" "5.93.0" -"@tanstack/react-query@^5.90.20": - version "5.90.20" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.90.20.tgz#42bb7018bfedc72f216b6e9b4052c919063f350b" - integrity sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw== +"@tanstack/react-query@^5.90.21": + version "5.90.21" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.90.21.tgz#e0eb40831a76510be438109435b8807ef63ab1b9" + integrity sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg== dependencies: "@tanstack/query-core" "5.90.20" @@ -1383,10 +1383,10 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -country-flag-icons@^1.6.12: - version "1.6.12" - resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.6.12.tgz#f32f9fd6f371bf3dc9389ed5cf85150b80b20c00" - integrity sha512-tWxbBylam6Fkkg0nu+112jmny4WomHXgmdTQFobs/+evTyizSc06bCp//HAh4W1i+g1m06uqlbPuyLC5mrimkQ== +country-flag-icons@^1.6.13: + version "1.6.13" + resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.6.13.tgz#744de466baf5d8189942ba08fc57167f74037282" + integrity sha512-mR9GoTXtj3zAXoZXBkb3J4QvyDllFEPtEfZvHb9U23TAHYXfkJyP03pRtZiR0spxo6Ibja3R/hn6a68T4LHBuA== css.escape@^1.5.1: version "1.5.1" @@ -1627,10 +1627,10 @@ globrex@^0.1.2: resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -happy-dom@^20.5.3: - version "20.5.3" - resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-20.5.3.tgz#0cc4159c4ca841cd388a45afe452060f41dbb84b" - integrity sha512-xqAxGnkRU0KNhheHpxb3uScqg/aehqUiVto/a9ApWMyNvnH9CAqHYq9dEPAovM6bOGbLstmTfGIln5ZIezEU0g== +happy-dom@^20.6.1: + version "20.6.1" + resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-20.6.1.tgz#af9cf1722871621334e0451b01548d551c91b515" + integrity sha512-+0vhESXXhFwkdjZnJ5DlmJIfUYGgIEEjzIjB+aKJbFuqlvvKyOi+XkI1fYbgYR9QCxG5T08koxsQ6HrQfa5gCQ== dependencies: "@types/node" ">=20.0.0" "@types/whatwg-mimetype" "^3.0.2"