diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3a2ae9e8f9..d44ec466d4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -8,7 +8,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v10 + - uses: actions/stale@v11 with: stale-issue-label: 'stale' stale-pr-label: 'stale' diff --git a/.version b/.version index 3b1fc7950f..7524906967 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.15.1 +2.16.0 diff --git a/README.md b/README.md index 5cd9be1c96..0ee51c3508 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@



- + diff --git a/SECURITY.md b/SECURITY.md index 66e4bb1f61..a1d30620c7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,8 +7,8 @@ Older versions are not actively maintained. | Version | Supported | | ------- | --------- | -| 2.15.x (latest) | :white_check_mark: | -| < 2.15.0 | :x: | +| 2.16.x (latest) | :white_check_mark: | +| < 2.16.0 | :x: | Docker images: `jc21/nginx-proxy-manager:latest`, `jc21/nginx-proxy-manager:2` diff --git a/backend/biome.json b/backend/biome.json index a0164fd99c..5d1794b5a9 100644 --- a/backend/biome.json +++ b/backend/biome.json @@ -1,91 +1,74 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignoreUnknown": false, - "includes": [ - "**/*.ts", - "**/*.tsx", - "**/*.js", - "**/*.jsx", - "!**/dist/**/*" - ] - }, - "formatter": { - "enabled": true, - "indentStyle": "tab", - "indentWidth": 4, - "lineWidth": 120, - "formatWithErrors": true - }, - "assist": { - "actions": { - "source": { - "organizeImports": { - "level": "on", - "options": { - "groups": [ - ":BUN:", - ":NODE:", - [ - "npm:*", - "npm:*/**" - ], - ":PACKAGE_WITH_PROTOCOL:", - ":URL:", - ":PACKAGE:", - [ - "/src/*", - "/src/**" - ], - [ - "/**" - ], - [ - "#*", - "#*/**" - ], - ":PATH:" - ] - } - } - } - } - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "correctness": { - "useUniqueElementIds": "off" - }, - "suspicious": { - "noExplicitAny": "off" - }, - "performance": { - "noDelete": "off" - }, - "nursery": "off", - "a11y": { - "useSemanticElements": "off", - "useValidAnchor": "off" - }, - "style": { - "noParameterAssign": "error", - "useAsConstAssertion": "error", - "useDefaultParameterLast": "error", - "useEnumInitializers": "error", - "useSelfClosingElements": "error", - "useSingleVarDeclarator": "error", - "noUnusedTemplateLiteral": "error", - "useNumberNamespace": "error", - "noInferrableTypes": "error", - "noUselessElse": "error" - } - } - } + "$schema": "https://biomejs.dev/schemas/2.5.10/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "!**/dist/**/*"] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "indentWidth": 4, + "lineWidth": 120, + "formatWithErrors": true + }, + "assist": { + "actions": { + "source": { + "organizeImports": { + "level": "on", + "options": { + "groups": [ + ":BUN:", + ":NODE:", + ["npm:*", "npm:*/**"], + ":PACKAGE_WITH_PROTOCOL:", + ":URL:", + ":PACKAGE:", + ["/src/*", "/src/**"], + ["/**"], + ["#*", "#*/**"], + ":PATH:" + ] + } + } + } + } + }, + "linter": { + "enabled": true, + "rules": { + "preset": "recommended", + "correctness": { + "useUniqueElementIds": "off" + }, + "suspicious": { + "noExplicitAny": "off" + }, + "performance": { + "noDelete": "off" + }, + "nursery": "off", + "a11y": { + "useSemanticElements": "off", + "useValidAnchor": "off" + }, + "style": { + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error" + } + } + } } diff --git a/backend/certbot/dns-plugins.json b/backend/certbot/dns-plugins.json index 220819404e..4467a27afe 100644 --- a/backend/certbot/dns-plugins.json +++ b/backend/certbot/dns-plugins.json @@ -32,12 +32,12 @@ "version": ">=0.1.0" }, "azure": { - "credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2", - "dependencies": "azure-mgmt-dns==8.2.0", + "credentials": "# Docs: https://cloudchristoph.github.io/certbot-dns-azure-modern/\n# Service principal with the \"DNS Zone Contributor\" role on the DNS zone\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = example-client-secret-not-real\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n# One line per DNS zone, format ZONE_NAME:RESOURCE_GROUP_ID\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/rg-dns", + "dependencies": "", "full_plugin_name": "dns-azure", "name": "Azure", - "package_name": "certbot-dns-azure", - "version": "~=2.6.1" + "package_name": "certbot-dns-azure-modern", + "version": "~=2.8.0" }, "baidu": { "credentials": "dns_baidu_access_key = 12345678\ndns_baidu_secret_key = 1234567890abcdef1234567890abcdef", @@ -231,6 +231,14 @@ "package_name": "certbot-plugin-edgedns", "version": "~=0.1.0" }, + "edgeone": { + "credentials": "dns_edgeone_secret_id = YOUR_TENCENTCLOUD_SECRET_ID\ndns_edgeone_secret_key = YOUR_TENCENTCLOUD_SECRET_KEY", + "dependencies": "", + "full_plugin_name": "dns-edgeone", + "name": "Tencent Cloud EdgeOne", + "package_name": "certbot-dns-edgeone", + "version": ">=0.1.0" + }, "eurodns": { "credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/dns-zones/", "dependencies": "", @@ -629,7 +637,7 @@ "full_plugin_name": "dns-tencentcloud", "name": "Tencent Cloud", "package_name": "certbot-dns-tencentcloud", - "version": "~=2.0.2" + "version": "~=2.1.1" }, "timeweb": { "credentials": "dns_timeweb_api_key = XXXXXXXXXXXXXXXXXXX", @@ -637,7 +645,7 @@ "full_plugin_name": "dns-timeweb", "name": "Timeweb Cloud", "package_name": "certbot-dns-timeweb", - "version": "~=1.0.1" + "version": "~=2.0.0" }, "transip": { "credentials": "dns_transip_username = my_username\ndns_transip_key_file = /etc/letsencrypt/transip-rsa.key", @@ -661,7 +669,7 @@ "full_plugin_name": "dns-websupport", "name": "Websupport.sk", "package_name": "certbot-dns-websupport", - "version": "~=2.0.1" + "version": "~=5.0.0" }, "wedos": { "credentials": "dns_wedos_user = \ndns_wedos_auth = ", @@ -686,5 +694,13 @@ "name": "RcodeZero", "package_name": "certbot-dns-rcode0", "version": "~=0.0.0.2" + }, + "lws": { + "credentials": "dns_lws_login = 123456\ndns_lws_api_key = YOUR_API_KEY", + "dependencies": "", + "full_plugin_name": "dns-lws", + "name": "LWS", + "package_name": "certbot-dns-lws", + "version": "~=1.0.0" } } diff --git a/backend/db.js b/backend/db.js index bf540f8a22..5b18d3a9a4 100644 --- a/backend/db.js +++ b/backend/db.js @@ -1,5 +1,5 @@ import knex from "knex"; -import {configGet, configHas} from "./lib/config.js"; +import { configGet, configHas } from "./lib/config.js"; let instance = null; @@ -23,8 +23,8 @@ const generateDbConfig = () => { user: cfg.user, password: cfg.password, database: cfg.name, - port: cfg.port, - ...(cfg.ssl ? { ssl: cfg.ssl } : {}) + port: cfg.port, + ...(cfg.ssl ? { ssl: cfg.ssl } : {}), }, migrations: { tableName: "migrations", @@ -37,6 +37,6 @@ const getInstance = () => { instance = knex(generateDbConfig()); } return instance; -} +}; export default getInstance; diff --git a/backend/internal/2fa.js b/backend/internal/2fa.js index 43307e02c3..db1c3385ea 100644 --- a/backend/internal/2fa.js +++ b/backend/internal/2fa.js @@ -161,12 +161,12 @@ const internal2fa = { } const result = await verify({ - token: code, - secret: auth.meta.totp_secret, - guardrails: createGuardrails({ - MIN_SECRET_BYTES: 10, - }), - }); + token: code, + secret: auth.meta.totp_secret, + guardrails: createGuardrails({ + MIN_SECRET_BYTES: 10, + }), + }); if (!result.valid) { throw new errs.AuthError("Invalid verification code"); @@ -288,11 +288,7 @@ const internal2fa = { }, getUserPasswordAuth: async (userId) => { - const auth = await authModel - .query() - .where("user_id", userId) - .andWhere("type", "password") - .first(); + const auth = await authModel.query().where("user_id", userId).andWhere("type", "password").first(); if (!auth) { throw new errs.ItemNotFoundError("Auth not found"); diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index 88bf9df523..1fdd65b6ab 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -2,7 +2,9 @@ import fs from "node:fs"; import batchflow from "batchflow"; import _ from "lodash"; import errs from "../lib/error.js"; +import { isMysql, isPostgres } from "../lib/config.js"; import utils from "../lib/utils.js"; +import db from "../db.js"; import { access as logger } from "../logger.js"; import accessListModel from "../models/access_list.js"; import accessListAuthModel from "../models/access_list_auth.js"; @@ -15,6 +17,38 @@ const omissions = () => { return ["is_deleted"]; }; +/** + * Find proxy hosts that reference an access list in their locations JSON. + * + * @param {Integer} accessListId + * @returns {Promise} + */ +const getProxyHostsUsingAccessListInLocations = async (accessListId) => { + let result; + if (isMysql()) { + const searchObj = JSON.stringify([{ access_list_id: accessListId }]); + result = await db().raw( + "SELECT id FROM proxy_host WHERE is_deleted = 0 AND JSON_CONTAINS(locations, ?, ?)", + [searchObj, "$"], + ); + } else if (isPostgres()) { + result = await db().raw( + "SELECT id FROM proxy_host WHERE is_deleted = 0 AND locations::jsonb @> ?::jsonb", + [JSON.stringify([{ access_list_id: accessListId }])], + ); + } else { + result = await db().raw( + "SELECT id FROM proxy_host WHERE is_deleted = 0 AND locations LIKE ?", + [`%"access_list_id":${accessListId}%`], + ); + } + // knex raw() returns [rows, metadata] for MySQL, { rows } for Postgres and rows for SQLite + if (!Array.isArray(result)) { + return result?.rows || []; + } + return (Array.isArray(result[0]) ? result[0] : result) || []; +}; + const internalAccessList = { /** * @param {Access} access @@ -66,7 +100,7 @@ const internalAccessList = { id: data.id, expand: ["owner", "items", "clients", "proxy_hosts.access_list.[clients,items]"], }, - true // skip masking + true, // skip masking ); // Audit log @@ -180,13 +214,31 @@ const internalAccessList = { id: data.id, expand: ["owner", "items", "clients", "proxy_hosts.[certificate,access_list.[clients,items]]"], }, - true // skip masking + true, // skip masking ); - await internalAccessList.build(freshRow) + await internalAccessList.build(freshRow); if (Number.parseInt(freshRow.proxy_host_count, 10)) { await internalNginx.bulkGenerateConfigs("proxy_host", freshRow.proxy_hosts); } + + // Also regenerate configs for proxy hosts that reference this access list in their locations + const locationHostRows = await getProxyHostsUsingAccessListInLocations(data.id); + if (locationHostRows?.length) { + const locationHostIds = locationHostRows.map((r) => r.id).filter((id) => { + // Exclude hosts already regenerated above + return !freshRow.proxy_hosts?.find((h) => h.id === id); + }); + if (locationHostIds.length) { + const locationHosts = await proxyHostModel.query() + .where("is_deleted", 0) + .whereIn("id", locationHostIds) + .allowGraph(proxyHostModel.defaultAllowGraph) + .withGraphFetched("[owner, certificate, access_list.[clients,items]]"); + await internalNginx.bulkGenerateConfigs("proxy_host", locationHosts); + } + } + await internalNginx.reload(); return internalAccessList.maskItems(freshRow); }, @@ -202,17 +254,13 @@ const internalAccessList = { */ get: async (access, data, skipMasking) => { const thisData = data || {}; - const accessData = await access.can("access_lists:get", thisData.id) + const accessData = await access.can("access_lists:get", thisData.id); const query = accessListModel .query() .select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count")) .leftJoin("proxy_host", function () { - this.on("proxy_host.access_list_id", "=", "access_list.id").andOn( - "proxy_host.is_deleted", - "=", - 0, - ); + this.on("proxy_host.access_list_id", "=", "access_list.id").andOn("proxy_host.is_deleted", "=", 0); }) .where("access_list.is_deleted", 0) .andWhere("access_list.id", thisData.id) @@ -267,28 +315,41 @@ const internalAccessList = { // 4. audit log // 1. update row to be deleted - await accessListModel - .query() - .where("id", row.id) - .patch({ - is_deleted: 1, - }); + await accessListModel.query().where("id", row.id).patch({ + is_deleted: 1, + }); // 2. update any proxy hosts that were using it (ignoring permissions) - if (row.proxy_hosts) { - await proxyHostModel - .query() - .where("access_list_id", "=", row.id) - .patch({ access_list_id: 0 }); + const affectedHostIds = new Set((row.proxy_hosts || []).map((h) => h.id)); + if (affectedHostIds.size) { + await proxyHostModel.query().where("access_list_id", "=", row.id).patch({ access_list_id: 0 }); + } - // 3. reconfigure those hosts, then reload nginx - // set the access_list_id to zero for these items - row.proxy_hosts.map((_val, idx) => { - row.proxy_hosts[idx].access_list_id = 0; - return true; - }); + // Also clear it from any proxy host locations using it, these will then inherit the host's access list + const locationHostRows = await getProxyHostsUsingAccessListInLocations(row.id); + for (const { id: hostId } of locationHostRows) { + const host = await proxyHostModel.query().where("id", hostId).first(); + if (host?.locations?.some((loc) => loc.access_list_id === row.id)) { + const updatedLocations = host.locations.map((loc) => { + if (loc.access_list_id === row.id) { + return { ...loc, access_list_id: 0 }; + } + return loc; + }); + await proxyHostModel.query().where("id", hostId).patch({ locations: updatedLocations }); + affectedHostIds.add(hostId); + } + } - await internalNginx.bulkGenerateConfigs("proxy_host", row.proxy_hosts); + // 3. reconfigure those hosts from fresh rows, then reload nginx + if (affectedHostIds.size) { + const affectedHosts = await proxyHostModel + .query() + .where("is_deleted", 0) + .whereIn("id", [...affectedHostIds]) + .allowGraph(proxyHostModel.defaultAllowGraph) + .withGraphFetched("[owner, certificate, access_list.[clients,items]]"); + await internalNginx.bulkGenerateConfigs("proxy_host", affectedHosts); } await internalNginx.reload(); @@ -325,11 +386,7 @@ const internalAccessList = { .query() .select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count")) .leftJoin("proxy_host", function () { - this.on("proxy_host.access_list_id", "=", "access_list.id").andOn( - "proxy_host.is_deleted", - "=", - 0, - ); + this.on("proxy_host.access_list_id", "=", "access_list.id").andOn("proxy_host.is_deleted", "=", 0); }) .where("access_list.is_deleted", 0) .groupBy("access_list.id") @@ -371,10 +428,7 @@ const internalAccessList = { * @returns {Promise} */ getCount: async (userId, visibility) => { - const query = accessListModel - .query() - .count("id as count") - .where("is_deleted", 0); + const query = accessListModel.query().count("id as count").where("is_deleted", 0); if (visibility !== "all") { query.andWhere("owner_user_id", userId); @@ -436,20 +490,24 @@ const internalAccessList = { } // 2. create empty access file - fs.writeFileSync(htpasswdFile, '', {encoding: 'utf8'}); + fs.writeFileSync(htpasswdFile, "", { encoding: "utf8" }); // 3. generate password for each user if (list.items.length) { await new Promise((resolve, reject) => { - batchflow(list.items).sequential() + batchflow(list.items) + .sequential() .each((_i, item, next) => { if (item.password?.length) { logger.info(`Adding: ${item.username}`); - utils.execFile('openssl', ['passwd', '-apr1', item.password]) + utils + .execFile("openssl", ["passwd", "-apr1", item.password]) .then((res) => { try { - fs.appendFileSync(htpasswdFile, `${item.username}:${res}\n`, {encoding: 'utf8'}); + fs.appendFileSync(htpasswdFile, `${item.username}:${res}\n`, { + encoding: "utf8", + }); } catch (err) { reject(err); } @@ -471,7 +529,7 @@ const internalAccessList = { }); }); } - } -} + }, +}; export default internalAccessList; diff --git a/backend/internal/audit-log.js b/backend/internal/audit-log.js index 02700dc5da..5155028c87 100644 --- a/backend/internal/audit-log.js +++ b/backend/internal/audit-log.js @@ -3,7 +3,6 @@ import { castJsonIfNeed } from "../lib/helpers.js"; import auditLogModel from "../models/audit-log.js"; const internalAuditLog = { - /** * All logs * @@ -46,11 +45,7 @@ const internalAuditLog = { get: async (access, data) => { await access.can("auditlog:list"); - const query = auditLogModel - .query() - .andWhere("id", data.id) - .allowGraph("[user]") - .first(); + const query = auditLogModel.query().andWhere("id", data.id).allowGraph("[user]").first(); if (typeof data.expand !== "undefined" && data.expand !== null) { query.withGraphFetched(`[${data.expand.join(", ")}]`); diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 6498422c61..963d2bb6a4 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -881,10 +881,20 @@ const internalCertificate = { const result = await utils.execFile(certbotCommand, args, adds.opts); logger.info(result); return result; - } catch (err) { - // Don't fail if file does not exist, so no need for action in the callback + } finally { + // Remove the credentials file whether certbot succeeded or failed. + // + // This cleanup used to sit in a catch block, so it only ran when issuance FAILED. + // A certificate that issued successfully left its DNS provider API credentials in + // /etc/letsencrypt/credentials for the entire life of that certificate. Nothing + // reads the file between certbot runs, so there is no reason to keep it: + // renewLetsEncryptSslWithDnsChallenge() writes it again immediately before each + // renewal. + // + // unlink is fire-and-forget with an empty callback. If the file is already gone + // that is the end state we wanted anyway, and a missing file must never turn a + // successful issuance into a failure. fs.unlink(credentialsLocation, () => {}); - throw err; } }, @@ -981,6 +991,43 @@ const internalCertificate = { `Renewing LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(", ")}`, ); + // certbot reads the DNS credentials back from the path recorded in the renewal config + // it wrote at issuance time, for example: + // + // authenticator = dns-cloudflare + // dns_cloudflare_credentials = /etc/letsencrypt/credentials/credentials-27 + // + // so the file has to be present for the duration of this run. Write it here and remove + // it again below rather than leaving it on disk between renewals. + // + // Leaving it is an avoidable exposure. Anything running as root - a compromised + // process, a script, malware - can read the token and use it to issue valid Let's + // Encrypt certificates for the domain. Those certificates are genuinely trusted, so + // traffic presented with them passes TLS inspection, IDS/IPS and DLP that would + // otherwise flag it, and an exfiltration path built on them looks like ordinary + // HTTPS. The exposure window should be one certbot run, not the life of the + // certificate. + // + // The value is not on the certificate object we were handed: renew() sources that from + // internalCertificate.get(), which pipes the row through utils.omitRow(omissions()) so + // meta.dns_provider_credentials can never travel out over the API. Read the row from + // the model directly to get at it. + const row = await certificateModel.query().where("id", certificate.id).first(); + const credentials = row?.meta?.dns_provider_credentials; + const credentialsLocation = `/etc/letsencrypt/credentials/credentials-${certificate.id}`; + + if (credentials) { + fs.mkdirSync("/etc/letsencrypt/credentials", { recursive: true }); + fs.writeFileSync(credentialsLocation, credentials, { mode: 0o600 }); + } else { + // Nothing stored to write. A certificate issued under the previous behaviour may + // still have its file on disk; leave it be and let certbot decide. Throwing here + // would break a renewal that would otherwise have succeeded. + logger.warn( + `No stored DNS credentials for Cert #${certificate.id}; relying on any existing ${credentialsLocation}`, + ); + } + const args = [ "renew", "--force-renewal", @@ -1008,9 +1055,19 @@ const internalCertificate = { logger.info(`Command: ${certbotCommand} ${args ? args.join(" ") : ""}`); - const result = await utils.execFile(certbotCommand, args, adds.opts); - logger.info(result); - return result; + try { + const result = await utils.execFile(certbotCommand, args, adds.opts); + logger.info(result); + return result; + } finally { + // Only clean up a file we put there ourselves. If `credentials` came back empty we + // wrote nothing, and an older file left on disk by the previous behaviour is the + // only thing keeping that certificate renewable - deleting it would break the next + // run for no gain. + if (credentials) { + fs.unlink(credentialsLocation, () => {}); + } + } }, /** diff --git a/backend/internal/dead-host.js b/backend/internal/dead-host.js index ee27e53cc5..6523e62892 100644 --- a/backend/internal/dead-host.js +++ b/backend/internal/dead-host.js @@ -54,9 +54,7 @@ const internalDeadHost = { thisData.advanced_config = ""; } - const row = await deadHostModel.query() - .insertAndFetch(thisData) - .then(utils.omitRow(omissions())); + const row = await deadHostModel.query().insertAndFetch(thisData).then(utils.omitRow(omissions())); // Add to audit log await internalAuditLog.add(access, { @@ -153,12 +151,8 @@ const internalDeadHost = { thisData = internalHost.cleanSslHstsData(thisData, row); - // do the row update - await deadHostModel - .query() - .where({id: data.id}) - .patch(data); + await deadHostModel.query().where({ id: data.id }).patch(data); // Add to audit log await internalAuditLog.add(access, { @@ -168,15 +162,18 @@ const internalDeadHost = { meta: thisData, }); - const thisRow = await internalDeadHost - .get(access, { - id: thisData.id, - expand: ["owner", "certificate"], - }); + const thisRow = await internalDeadHost.get(access, { + id: thisData.id, + expand: ["owner", "certificate"], + }); // Configure nginx - const newMeta = await internalNginx.configure(deadHostModel, "dead_host", row); - row.meta = newMeta; + if (!thisRow.enabled) { + // No need to add nginx config if host is disabled + return _.omit(internalHost.cleanRowCertificateMeta(thisRow), omissions()); + } + const newMeta = await internalNginx.configure(deadHostModel, "dead_host", thisRow); + thisRow.meta = newMeta; return _.omit(internalHost.cleanRowCertificateMeta(thisRow), omissions()); }, @@ -224,18 +221,15 @@ const internalDeadHost = { * @returns {Promise} */ delete: async (access, data) => { - await access.can("dead_hosts:delete", data.id) + await access.can("dead_hosts:delete", data.id); const row = await internalDeadHost.get(access, { id: data.id }); if (!row?.id) { throw new errs.ItemNotFoundError(data.id); } - await deadHostModel - .query() - .where("id", row.id) - .patch({ - is_deleted: 1, - }); + await deadHostModel.query().where("id", row.id).patch({ + is_deleted: 1, + }); // Delete Nginx Config await internalNginx.deleteConfig("dead_host", row); @@ -259,7 +253,7 @@ const internalDeadHost = { * @returns {Promise} */ enable: async (access, data) => { - await access.can("dead_hosts:update", data.id) + await access.can("dead_hosts:update", data.id); const row = await internalDeadHost.get(access, { id: data.id, expand: ["certificate", "owner"], @@ -273,12 +267,9 @@ const internalDeadHost = { row.enabled = 1; - await deadHostModel - .query() - .where("id", row.id) - .patch({ - enabled: 1, - }); + await deadHostModel.query().where("id", row.id).patch({ + enabled: 1, + }); // Configure nginx await internalNginx.configure(deadHostModel, "dead_host", row); @@ -301,7 +292,7 @@ const internalDeadHost = { * @returns {Promise} */ disable: async (access, data) => { - await access.can("dead_hosts:update", data.id) + await access.can("dead_hosts:update", data.id); const row = await internalDeadHost.get(access, { id: data.id }); if (!row?.id) { throw new errs.ItemNotFoundError(data.id); @@ -312,12 +303,9 @@ const internalDeadHost = { row.enabled = 0; - await deadHostModel - .query() - .where("id", row.id) - .patch({ - enabled: 0, - }); + await deadHostModel.query().where("id", row.id).patch({ + enabled: 0, + }); // Delete Nginx Config await internalNginx.deleteConfig("dead_host", row); @@ -342,7 +330,7 @@ const internalDeadHost = { * @returns {Promise} */ getAll: async (access, expand, searchQuery) => { - const accessData = await access.can("dead_hosts:list") + const accessData = await access.can("dead_hosts:list"); const query = deadHostModel .query() .where("is_deleted", 0) diff --git a/backend/internal/log-viewer.js b/backend/internal/log-viewer.js new file mode 100644 index 0000000000..2b1b8e9675 --- /dev/null +++ b/backend/internal/log-viewer.js @@ -0,0 +1,229 @@ +import fs from "node:fs"; +import errs from "../lib/error.js"; +import internalDeadHost from "./dead-host.js"; +import internalProxyHost from "./proxy-host.js"; +import internalRedirectionHost from "./redirection-host.js"; +import internalStream from "./stream.js"; + +const SYSTEM_LOG_FILE = "/data/logs/backend.log"; +const LETSENCRYPT_LOG_FILE = "/data/logs/letsencrypt.log"; + +// Matches the access_log/error_log paths written by the nginx templates +// (see backend/templates/{proxy_host,redirection_host,dead_host,stream}.conf). +// This is a fixed, server-side lookup table - a host log path is always derived +// from a validated `host_type` enum + numeric `host_id`, never from a client-supplied +// path or filename, so there is no path-traversal surface here. +const HOST_FILE_PREFIX = { + proxy: "proxy-host", + redirection: "redirection-host", + dead: "dead-host", + stream: "stream", +}; + +const DEFAULT_LINES = 200; +const MAX_LINES = 1000; +const CHUNK_SIZE = 64 * 1024; +// Never scan further back than this, regardless of how many lines were requested, +// so a huge or pathological log file can't turn a single request into unbounded I/O. +const MAX_SCAN_BYTES = 5 * 1024 * 1024; + +/** + * Reads at most `maxLines` lines from the end of a file, without loading the + * whole file into memory. Reads backwards in fixed-size chunks until enough + * newlines have been seen, the start of the file is reached, or the hard + * MAX_SCAN_BYTES ceiling is hit. + * + * @param {String} filePath + * @param {Number} maxLines + * @returns {Promise<{lines: String[], size: Number, truncated: Boolean}>} + */ +const readLastLines = async (filePath, maxLines) => { + let handle; + try { + handle = await fs.promises.open(filePath, "r"); + const stat = await handle.stat(); + const { size } = stat; + + if (size === 0) { + return { lines: [], size: 0, truncated: false }; + } + + let position = size; + let scanned = 0; + let newlineCount = 0; + const chunks = []; + + while (position > 0 && newlineCount <= maxLines && scanned < MAX_SCAN_BYTES) { + const readSize = Math.min(CHUNK_SIZE, position); + position -= readSize; + const buffer = Buffer.alloc(readSize); + await handle.read(buffer, 0, readSize, position); + scanned += readSize; + for (let i = buffer.length - 1; i >= 0; i--) { + if (buffer[i] === 0x0a) newlineCount++; + } + chunks.unshift(buffer); + } + + const truncated = position > 0 && scanned >= MAX_SCAN_BYTES; + + // If we didn't start reading from byte 0, the first line in our buffer is only + // partial *unless* it happens that `position` landed exactly on a line boundary + // (the byte right before it is a newline) - check that one byte to avoid + // silently dropping a perfectly valid line. + let startsOnLineBoundary = position === 0; + if (position > 0) { + const boundaryByte = Buffer.alloc(1); + await handle.read(boundaryByte, 0, 1, position - 1); + startsOnLineBoundary = boundaryByte[0] === 0x0a; + } + + const text = Buffer.concat(chunks).toString("utf8"); + const allLines = text.split("\n"); + + if (!startsOnLineBoundary && allLines.length > 0) { + allLines.shift(); + } + // Drop the trailing empty element caused by a final trailing newline. + if (allLines.length > 0 && allLines[allLines.length - 1] === "") { + allLines.pop(); + } + + return { lines: allLines.slice(-maxLines), size, truncated }; + } finally { + if (handle) { + await handle.close(); + } + } +}; + +/** + * Resolves a validated {type, host_type, host_id, channel} selection to the + * fixed, absolute path of the log file on disk. Throws if the combination + * isn't a recognised source. + * + * `channel` ("access" | "error") picks which of the two log files nginx writes + * per host - it's deliberately not named "stream" to avoid confusion with the + * "stream" host_type (TCP/UDP stream hosts). + * + * @param {Object} data + * @returns {String} + */ +const resolveFilePath = (data) => { + switch (data.type) { + case "system": + return SYSTEM_LOG_FILE; + case "letsencrypt": + return LETSENCRYPT_LOG_FILE; + case "host": { + const prefix = HOST_FILE_PREFIX[data.host_type]; + if (!prefix || !data.host_id || !["access", "error"].includes(data.channel)) { + throw new errs.ValidationError("Invalid host log source"); + } + return `/data/logs/${prefix}-${data.host_id}_${data.channel}.log`; + } + default: + throw new errs.ItemNotFoundError(data.type); + } +}; + +/** + * @param {Array} rows + * @returns {Array} + */ +const toHostOptions = (rows) => + rows.map((row) => ({ + id: row.id, + label: Array.isArray(row.domain_names) ? row.domain_names.join(", ") : `Host #${row.id}`, + })); + +const internalLogViewer = { + /** + * Lists the log sources available for the log viewer: the system (backend) + * log, the Let's Encrypt (certbot) log, and one entry per host the caller + * can see, for each host type. + * + * @param {Access} access + * @returns {Promise} + */ + listSources: async (access) => { + await access.can("logs:list"); + + const [proxyHosts, redirectionHosts, deadHosts, streams] = await Promise.all([ + internalProxyHost.getAll(access), + internalRedirectionHost.getAll(access), + internalDeadHost.getAll(access), + internalStream.getAll(access), + ]); + + return { + system: { label: "System" }, + letsencrypt: { label: "Let's Encrypt" }, + hosts: { + proxy: toHostOptions(proxyHosts), + redirection: toHostOptions(redirectionHosts), + dead: toHostOptions(deadHosts), + stream: streams.map((row) => ({ + id: row.id, + label: `Port ${row.incoming_port} → ${row.forwarding_host}:${row.forwarding_port}`, + })), + }, + }; + }, + + /** + * Returns the last N lines of the requested log source, optionally + * filtered by level and/or a plain-text search term. + * + * @param {Access} access + * @param {Object} data + * @param {String} data.type "system" | "letsencrypt" | "host" + * @param {String} [data.host_type] "proxy" | "redirection" | "dead" | "stream" + * @param {Number} [data.host_id] + * @param {String} [data.channel] "access" | "error" + * @param {Number} [data.lines] + * @param {String} [data.level] + * @param {String} [data.search] + * @returns {Promise} + */ + tail: async (access, data) => { + await access.can("logs:list"); + + const filePath = resolveFilePath(data); + const lines = Math.min(Math.max(data.lines || DEFAULT_LINES, 1), MAX_LINES); + + let result; + try { + result = await readLastLines(filePath, lines); + } catch (err) { + if (err.code === "ENOENT") { + return { lines: [], size: 0, truncated: false, exists: false }; + } + throw err; + } + + let outputLines = result.lines; + + // Only the system log is written in our own "LEVEL [scope]" format - level + // filtering on nginx/certbot lines would just match nothing and look like an + // empty log, so the filter is a no-op for any other source. + if (data.type === "system" && data.level) { + const needle = ` ${data.level.toUpperCase().padEnd(7)} `; + outputLines = outputLines.filter((line) => line.includes(needle)); + } + + if (data.search) { + const needle = data.search.toLowerCase(); + outputLines = outputLines.filter((line) => line.toLowerCase().includes(needle)); + } + + return { + lines: outputLines, + size: result.size, + truncated: result.truncated, + exists: true, + }; + }, +}; + +export default internalLogViewer; diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index fe84607f96..a50e0780dc 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -1,10 +1,12 @@ import fs from "node:fs"; +import net from "node:net"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import _ from "lodash"; import errs from "../lib/error.js"; import utils from "../lib/utils.js"; import { debug, nginx as logger } from "../logger.js"; +import accessListModel from "../models/access_list.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -34,7 +36,7 @@ const internalNginx = { // We're deleting this config regardless. // Don't throw errors, as the file may not exist at all // Delete the .err file too - return internalNginx.deleteConfig(host_type, host, false, true); + return internalNginx.deleteConfig(host_type, host, true); }) .then(() => { return internalNginx.generateConfig(host_type, host); @@ -83,10 +85,12 @@ const internalNginx = { meta: combined_meta, }) .then(() => { - internalNginx.renameConfigAsError(host_type, host); + // Keep the failed config as a .err file for inspection + return internalNginx.renameConfigAsError(host_type, host); }) .then(() => { - return internalNginx.deleteConfig(host_type, host, true); + // The rename removed the live config already, don't touch the .err file + return internalNginx.deleteConfig(host_type, host, false); }); }); }) @@ -165,6 +169,24 @@ const internalNginx = { host.locations[i], ); + // A location with its own access list overrides the host's, + // otherwise it inherits the host's access list + let locationAccessList = null; + if (locationCopy.access_list_id > 0 && locationCopy.access_list_id !== host.access_list?.id) { + locationAccessList = await accessListModel + .query() + .where("is_deleted", 0) + .andWhere("id", locationCopy.access_list_id) + .withGraphFetched("[clients,items]") + .first(); + } + if (locationAccessList) { + locationCopy.access_list = locationAccessList; + } else { + locationCopy.access_list_id = host.access_list_id; + locationCopy.access_list = host.access_list; + } + if (locationCopy.forward_host.indexOf("/") > -1) { const splitted = locationCopy.forward_host.split("/"); @@ -176,7 +198,9 @@ const internalNginx = { } }; - locationRendering().then(() => resolve(renderedLocations)); + locationRendering() + .then(() => resolve(renderedLocations)) + .catch(reject); }); }, @@ -217,10 +241,21 @@ const internalNginx = { } // For redirection hosts, if the scheme is not http or https, set it to $scheme - if (nice_host_type === "redirection_host" && ['http', 'https'].indexOf(host.forward_scheme.toLowerCase()) === -1) { + if ( + nice_host_type === "redirection_host" && + ["http", "https"].indexOf(host.forward_scheme.toLowerCase()) === -1 + ) { host.forward_scheme = "$scheme"; } + // A stream forwarding to an IPv6 literal must have the address wrapped in + // square brackets before nginx appends ":". Without the brackets nginx + // reads the trailing ":" as part of the address and rejects the upstream + // ("invalid port in upstream"), so the stream saves but never activates (#5740). + if (nice_host_type === "stream" && net.isIPv6(host.forwarding_host)) { + host.forwarding_host = `[${host.forwarding_host}]`; + } + if (host.locations) { //logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2)); origLocations = [].concat(host.locations); @@ -257,6 +292,9 @@ const internalNginx = { debug(logger, `Could not write ${filename}:`, err.message); reject(new errs.ConfigurationError(err.message)); }); + }).catch((err) => { + debug(logger, `Could not render locations for ${filename}:`, err.message); + reject(new errs.ConfigurationError(err.message)); }); }); }, @@ -375,8 +413,8 @@ const internalNginx = { const config_file_err = `${config_file}.err`; return new Promise((resolve /*, reject*/) => { - fs.unlink(config_file, () => { - // ignore result, continue + fs.unlink(config_file_err, () => { + // ignore result, a previous .err file may not exist fs.rename(config_file, config_file_err, () => { // also ignore result, as this is a debugging informative file anyway resolve(); diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 2c159d48ad..eac0c148aa 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -83,28 +83,28 @@ const internalProxyHost = { expand: ["certificate", "owner", "access_list.[clients,items]"], }); }) - .then((row) => { - // Configure nginx - return internalNginx.configure(proxyHostModel, "proxy_host", row).then(() => { + .then(async (row) => { + // Configure nginx + return internalNginx.configure(proxyHostModel, "proxy_host", row).then(() => { + return row; + }); + }) + .then((row) => { + // Audit log + thisData.meta = _.assign({}, thisData.meta || {}, row.meta); + + // Add to audit log + return internalAuditLog + .add(access, { + action: "created", + object_type: "proxy-host", + object_id: row.id, + meta: thisData, + }) + .then(() => { return row; }); - }) - .then((row) => { - // Audit log - thisData.meta = _.assign({}, thisData.meta || {}, row.meta); - - // Add to audit log - return internalAuditLog - .add(access, { - action: "created", - object_type: "proxy-host", - object_id: row.id, - meta: thisData, - }) - .then(() => { - return row; - }); - }); + }); }, /** @@ -202,24 +202,24 @@ const internalProxyHost = { }); }); }) - .then(() => { - return internalProxyHost - .get(access, { - id: thisData.id, - expand: ["owner", "certificate", "access_list.[clients,items]"], - }) - .then((row) => { - if (!row.enabled) { - // No need to add nginx config if host is disabled - return row; - } - // Configure nginx - return internalNginx.configure(proxyHostModel, "proxy_host", row).then((new_meta) => { - row.meta = new_meta; - return _.omit(internalHost.cleanRowCertificateMeta(row), omissions()); - }); + .then(() => { + return internalProxyHost + .get(access, { + id: thisData.id, + expand: ["owner", "certificate", "access_list.[clients,items]"], + }) + .then(async (row) => { + if (!row.enabled) { + // No need to add nginx config if host is disabled + return row; + } + // Configure nginx + return internalNginx.configure(proxyHostModel, "proxy_host", row).then((new_meta) => { + row.meta = new_meta; + return _.omit(internalHost.cleanRowCertificateMeta(row), omissions()); }); - }); + }); + }); }, /** @@ -326,39 +326,36 @@ const internalProxyHost = { expand: ["certificate", "owner", "access_list"], }); }) - .then((row) => { - if (!row?.id) { - throw new errs.ItemNotFoundError(data.id); - } - if (row.enabled) { - throw new errs.ValidationError("Host is already enabled"); - } + .then(async (row) => { + if (!row?.id) { + throw new errs.ItemNotFoundError(data.id); + } + if (row.enabled) { + throw new errs.ValidationError("Host is already enabled"); + } + + row.enabled = 1; + + await proxyHostModel + .query() + .where("id", row.id) + .patch({ + enabled: 1, + }); - row.enabled = 1; + // Configure nginx + await internalNginx.configure(proxyHostModel, "proxy_host", row); - return proxyHostModel - .query() - .where("id", row.id) - .patch({ - enabled: 1, - }) - .then(() => { - // Configure nginx - return internalNginx.configure(proxyHostModel, "proxy_host", row); - }) - .then(() => { - // Add to audit log - return internalAuditLog.add(access, { - action: "enabled", - object_type: "proxy-host", - object_id: row.id, - meta: _.omit(row, omissions()), - }); - }); - }) - .then(() => { - return true; + // Add to audit log + await internalAuditLog.add(access, { + action: "enabled", + object_type: "proxy-host", + object_id: row.id, + meta: _.omit(row, omissions()), }); + + return true; + }); }, /** diff --git a/backend/internal/token.js b/backend/internal/token.js index 126283e2dd..67255b2134 100644 --- a/backend/internal/token.js +++ b/backend/internal/token.js @@ -38,11 +38,7 @@ export default { throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH); } - const auth = await authModel - .query() - .where("user_id", "=", user.id) - .where("type", "=", "password") - .first(); + const auth = await authModel.query().where("user_id", "=", user.id).where("type", "=", "password").first(); if (!auth) { throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH); @@ -50,10 +46,7 @@ export default { const valid = await auth.verifyPassword(data.secret); if (!valid) { - throw new errs.AuthError( - ERROR_MESSAGE_INVALID_AUTH, - ERROR_MESSAGE_INVALID_AUTH_I18N, - ); + throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH, ERROR_MESSAGE_INVALID_AUTH_I18N); } if (data.scope !== "user" && _.indexOf(user.roles, data.scope) === -1) { @@ -171,7 +164,7 @@ export default { } // Check scope - if (!tokenData.scope || tokenData.scope[0] !== "2fa-challenge") { + if (tokenData.scope?.[0] !== "2fa-challenge") { throw new errs.AuthError("Invalid challenge token"); } @@ -183,10 +176,7 @@ export default { // Verify 2FA code const valid = await twoFactor.verifyForLogin(userId, code); if (!valid) { - throw new errs.AuthError( - ERROR_MESSAGE_INVALID_2FA, - ERROR_MESSAGE_INVALID_2FA_I18N, - ); + throw new errs.AuthError(ERROR_MESSAGE_INVALID_2FA, ERROR_MESSAGE_INVALID_2FA_I18N); } // Create full token diff --git a/backend/internal/user.js b/backend/internal/user.js index 56a5ea8598..8dd86f461a 100644 --- a/backend/internal/user.js +++ b/backend/internal/user.js @@ -257,11 +257,9 @@ const internalUser = { }, deleteAll: async () => { - await userModel - .query() - .patch({ - is_deleted: 1, - }); + await userModel.query().patch({ + is_deleted: 1, + }); }, /** @@ -390,11 +388,21 @@ const internalUser = { .andWhere("type", data.type) .first() .then((existing_auth) => { + // Stamped here rather than read off modified_on, because it is compared against a + // token's `iat` and the two only line up when the same clock writes both. The + // database clock is a different one: with the app on one timezone and the database + // on another, its timestamps come back hours away from where Node thinks it is. + const password_changed_at = Math.floor(Date.now() / 1000); + if (existing_auth) { // patch + const meta = existing_auth.meta || {}; + meta.password_changed_at = password_changed_at; + return authModel.query().where("user_id", user.id).andWhere("type", data.type).patch({ type: data.type, // This is required for the model to encrypt on save secret: data.secret, + meta, }); } // insert @@ -402,7 +410,7 @@ const internalUser = { user_id: user.id, type: data.type, secret: data.secret, - meta: {}, + meta: { password_changed_at }, }); }) .then(() => { diff --git a/backend/knexfile.js b/backend/knexfile.js index 607552f6fc..0e7e5e5afb 100644 --- a/backend/knexfile.js +++ b/backend/knexfile.js @@ -1,19 +1,19 @@ module.exports = { development: { - client: 'mysql2', + client: "mysql2", migrations: { - tableName: 'migrations', - stub: 'lib/migrate_template.js', - directory: 'migrations' - } + tableName: "migrations", + stub: "lib/migrate_template.js", + directory: "migrations", + }, }, production: { - client: 'mysql2', + client: "mysql2", migrations: { - tableName: 'migrations', - stub: 'lib/migrate_template.js', - directory: 'migrations' - } - } + tableName: "migrations", + stub: "lib/migrate_template.js", + directory: "migrations", + }, + }, }; diff --git a/backend/lib/access.js b/backend/lib/access.js index a4dec5c4dd..d119a4f925 100644 --- a/backend/lib/access.js +++ b/backend/lib/access.js @@ -12,6 +12,7 @@ import { fileURLToPath } from "node:url"; import Ajv from "ajv/dist/2020.js"; import _ from "lodash"; import { access as logger } from "../logger.js"; +import authModel from "../models/auth.js"; import proxyHostModel from "../models/proxy_host.js"; import TokenModel from "../models/token.js"; import userModel from "../models/user.js"; @@ -80,6 +81,22 @@ export default function (tokenString) { if (!ok) { throw new errs.AuthError("Invalid token scope for User"); } + + // A token issued before the password was last changed is no longer valid: taking an account + // back from whoever has the old password has to end the sessions that password opened. + const auth = await authModel + .query() + .where("user_id", "=", user.id) + .where("type", "=", "password") + .first(); + + // Both sides come from the same clock and in the same unit, whole seconds since + // the epoch: `setPassword` stamps the marker and `jsonwebtoken` stamps `iat`. + const changedAt = auth?.meta?.password_changed_at; + if (changedAt && typeof tokenData.iat === "number" && tokenData.iat < changedAt) { + throw new errs.TokenRevokedError("Token was issued before the password was changed"); + } + initialised = true; userRoles = user.roles; permissions = user.permissions; @@ -119,10 +136,7 @@ export default function (tokenString) { // Proxy Hosts case "proxy_hosts": { - const query = proxyHostModel - .query() - .select("id") - .andWhere("is_deleted", 0); + const query = proxyHostModel.query().select("id").andWhere("is_deleted", 0); if (permissions.visibility === "user") { query.andWhere("owner_user_id", tokenUserId); @@ -271,7 +285,12 @@ export default function (tokenString) { err.permission = permission; err.permission_data = data; logger.error(permission, data, err.message); - throw errs.PermissionError("Permission Denied", err); + // A revoked token is not a permission problem, and the client can tell: the frontend + // clears the session on a 401 and on nothing else. + if (err instanceof errs.TokenRevokedError) { + throw err; + } + throw new errs.PermissionError("Permission Denied", err); } }, }; diff --git a/backend/lib/access/logs-list.json b/backend/lib/access/logs-list.json new file mode 100644 index 0000000000..aeadc94ba9 --- /dev/null +++ b/backend/lib/access/logs-list.json @@ -0,0 +1,7 @@ +{ + "anyOf": [ + { + "$ref": "roles#/definitions/admin" + } + ] +} diff --git a/backend/lib/config.js b/backend/lib/config.js index a491c190e8..59cb6598de 100644 --- a/backend/lib/config.js +++ b/backend/lib/config.js @@ -2,13 +2,13 @@ import fs from "node:fs"; import NodeRSA from "node-rsa"; import { global as logger } from "../logger.js"; -const keysFile = '/data/keys.json'; -const mysqlEngine = 'mysql2'; -const postgresEngine = 'pg'; -const sqliteClientName = 'better-sqlite3'; +const keysFile = "/data/keys.json"; +const mysqlEngine = "mysql2"; +const postgresEngine = "pg"; +const sqliteClientName = "better-sqlite3"; // Not used for new setups anymore but may exist in legacy setups -const legacySqliteClientName = 'sqlite3'; +const legacySqliteClientName = "sqlite3"; let instance = null; @@ -40,14 +40,20 @@ const configure = () => { } } - const toBool = (v) => /^(1|true|yes|on)$/i.test((v || '').trim()); + const toBool = (v) => /^(1|true|yes|on)$/i.test((v || "").trim()); - const envMysqlHost = process.env.DB_MYSQL_HOST || null; - const envMysqlUser = process.env.DB_MYSQL_USER || null; - const envMysqlName = process.env.DB_MYSQL_NAME || null; - const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL); - const envMysqlSSLRejectUnauthorized = process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined ? true : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED); - const envMysqlSSLVerifyIdentity = process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined ? true : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY); + const envMysqlHost = process.env.DB_MYSQL_HOST || null; + const envMysqlUser = process.env.DB_MYSQL_USER || null; + const envMysqlName = process.env.DB_MYSQL_NAME || null; + const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL); + const envMysqlSSLRejectUnauthorized = + process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined + ? true + : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED); + const envMysqlSSLVerifyIdentity = + process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined + ? true + : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY); if (envMysqlHost && envMysqlUser && envMysqlName) { // we have enough mysql creds to go with mysql logger.info("Using MySQL configuration"); @@ -58,8 +64,10 @@ const configure = () => { port: process.env.DB_MYSQL_PORT || 3306, user: envMysqlUser, password: process.env.DB_MYSQL_PASSWORD, - name: envMysqlName, - ssl: envMysqlSSL ? { rejectUnauthorized: envMysqlSSLRejectUnauthorized, verifyIdentity: envMysqlSSLVerifyIdentity } : false, + name: envMysqlName, + ssl: envMysqlSSL + ? { rejectUnauthorized: envMysqlSSLRejectUnauthorized, verifyIdentity: envMysqlSSLVerifyIdentity } + : false, }, keys: getKeys(), }; @@ -137,7 +145,7 @@ const generateKeys = () => { // Write keys config try { - fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2)); + fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2), { mode: 0o600 }); } catch (err) { logger.error(`Could not write JWT key pair to config file: ${keysFile}: ${err.message}`); process.exit(1); @@ -222,7 +230,7 @@ const isDebugMode = () => !!process.env.DEBUG; * * @returns {boolean} */ -const isCI = () => process.env.CI === 'true' && process.env.DEBUG === 'true'; +const isCI = () => process.env.CI === "true" && process.env.DEBUG === "true"; /** * Returns a public key @@ -259,4 +267,16 @@ const useLetsencryptServer = () => { return null; }; -export { isCI, configHas, configGet, isSqlite, isMysql, isPostgres, isDebugMode, getPrivateKey, getPublicKey, useLetsencryptStaging, useLetsencryptServer }; +export { + isCI, + configHas, + configGet, + isSqlite, + isMysql, + isPostgres, + isDebugMode, + getPrivateKey, + getPublicKey, + useLetsencryptStaging, + useLetsencryptServer, +}; diff --git a/backend/lib/error.js b/backend/lib/error.js index d7dbf0c965..060988904d 100644 --- a/backend/lib/error.js +++ b/backend/lib/error.js @@ -22,6 +22,15 @@ const errs = { this.status = 404; }, + TokenRevokedError: function (message, previous) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.previous = previous; + this.message = message; + this.public = true; + this.status = 401; + }, + AuthError: function (message, messageI18n, previous) { Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; diff --git a/backend/lib/express/pagination.js b/backend/lib/express/pagination.js index 188df2779d..457c954d2d 100644 --- a/backend/lib/express/pagination.js +++ b/backend/lib/express/pagination.js @@ -1,4 +1,4 @@ -import _ from "lodash"; +import _ from "lodash"; export default (default_sort, default_offset, default_limit, max_limit) => { /** diff --git a/backend/lib/express/user-id-from-me.js b/backend/lib/express/user-id-from-me.js index 9c29ba2721..5035d8fdd9 100644 --- a/backend/lib/express/user-id-from-me.js +++ b/backend/lib/express/user-id-from-me.js @@ -1,6 +1,6 @@ export default (req, res, next) => { - if (req.params.user_id === 'me' && res.locals.access) { - req.params.user_id = res.locals.access.token.get('attrs').id; + if (req.params.user_id === "me" && res.locals.access) { + req.params.user_id = res.locals.access.token.get("attrs").id; } else { req.params.user_id = Number.parseInt(req.params.user_id, 10); } diff --git a/backend/lib/validator/api.js b/backend/lib/validator/api.js index 6c738d5097..0597ef635b 100644 --- a/backend/lib/validator/api.js +++ b/backend/lib/validator/api.js @@ -1,3 +1,4 @@ +import net from "node:net"; import Ajv from "ajv/dist/2020.js"; import errs from "../error.js"; @@ -9,6 +10,8 @@ const ajv = new Ajv({ coerceTypes: true, }); +ajv.addFormat("ipv6", { type: "string", validate: (value) => net.isIPv6(value) }); + /** * @param {Object} schema * @param {Object} payload @@ -24,21 +27,17 @@ const apiValidator = async (schema, payload /*, description*/) => { throw new errs.ValidationError("Payload is undefined"); } - const validate = ajv.compile(schema); const valid = validate(payload); - if (valid && !validate.errors) { return payload; } - - const message = ajv.errorsText(validate.errors); const err = new errs.ValidationError(message); - err.debug = {validationErrors: validate.errors, payload}; + err.debug = { validationErrors: validate.errors, payload }; throw err; }; diff --git a/backend/lib/validator/index.js b/backend/lib/validator/index.js index 5f2586fd67..767353f61f 100644 --- a/backend/lib/validator/index.js +++ b/backend/lib/validator/index.js @@ -1,4 +1,5 @@ -import Ajv from 'ajv/dist/2020.js'; +import net from "node:net"; +import Ajv from "ajv/dist/2020.js"; import _ from "lodash"; import commonDefinitions from "../../schema/common.json" with { type: "json" }; import errs from "../error.js"; @@ -14,6 +15,8 @@ const ajv = new Ajv({ schemas: [commonDefinitions], }); +ajv.addFormat("ipv6", { type: "string", validate: (value) => net.isIPv6(value) }); + /** * * @param {Object} schema diff --git a/backend/logger.js b/backend/logger.js index 2b60dbff7b..cd845d5fbb 100644 --- a/backend/logger.js +++ b/backend/logger.js @@ -1,3 +1,5 @@ +import fs from "node:fs"; +import path from "node:path"; import signale from "signale"; import { isDebugMode } from "./lib/config.js"; @@ -5,17 +7,115 @@ const opts = { logLevel: "info", }; -const global = new signale.Signale({ scope: "Global ", ...opts }); -const migrate = new signale.Signale({ scope: "Migrate ", ...opts }); -const express = new signale.Signale({ scope: "Express ", ...opts }); -const access = new signale.Signale({ scope: "Access ", ...opts }); -const nginx = new signale.Signale({ scope: "Nginx ", ...opts }); -const ssl = new signale.Signale({ scope: "SSL ", ...opts }); -const certbot = new signale.Signale({ scope: "Certbot ", ...opts }); -const importer = new signale.Signale({ scope: "Importer ", ...opts }); -const setup = new signale.Signale({ scope: "Setup ", ...opts }); -const ipRanges = new signale.Signale({ scope: "IP Ranges", ...opts }); -const remoteVersion = new signale.Signale({ scope: "Remote Version", ...opts }); +// Methods that are actually used across the codebase (see grep of `.info(`, `.warn(`, etc). +// Only these are mirrored to the log file - decorative signale methods (star, note, watch, ...) +// are left console-only since they carry no diagnostic value worth persisting. +const PERSISTED_METHODS = ["info", "warn", "error", "debug", "success", "fatal", "complete"]; + +const LOG_FILE = "/data/logs/backend.log"; +// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI colour codes before writing to disk +const ANSI_PATTERN = /\x1b\[[0-9;]*m/g; + +let fileStream = null; +let lastOpenAttempt = 0; +// If the file can't be opened (eg. running outside the standard Docker image, or in +// CI without /data), don't retry on every single log call - but do retry periodically +// so a transient issue (disk full, permissions fixed later) recovers without a restart. +const REOPEN_COOLDOWN_MS = 30 * 1000; + +/** + * Lazily opens the backend log file for appending. If the directory isn't writable, + * file logging is silently disabled and console logging continues unaffected. + * + * @returns {import('node:fs').WriteStream|null} + */ +const getFileStream = () => { + if (fileStream) { + return fileStream; + } + + const now = Date.now(); + if (now - lastOpenAttempt < REOPEN_COOLDOWN_MS) { + return null; + } + lastOpenAttempt = now; + + try { + fs.mkdirSync(path.dirname(LOG_FILE), { recursive: true }); + const stream = fs.createWriteStream(LOG_FILE, { flags: "a" }); + stream.on("error", () => { + fileStream = null; + }); + fileStream = stream; + } catch (_err) { + fileStream = null; + } + return fileStream; +}; + +/** + * Formats and appends a single log line to the backend log file. + * Never throws - a failure here must never take down the application. + * + * @param {String} level + * @param {String} scope + * @param {Array} args + */ +const writeToFile = (level, scope, args) => { + const stream = getFileStream(); + if (!stream) { + return; + } + + const message = args + .map((arg) => { + if (typeof arg === "string") return arg; + if (arg instanceof Error) return arg.stack || arg.message; + try { + return JSON.stringify(arg); + } catch (_err) { + return String(arg); + } + }) + .join(" ") + .replace(ANSI_PATTERN, ""); + + const line = `${new Date().toISOString()} ${level.toUpperCase().padEnd(7)} [${scope.trim()}] ${message}\n`; + stream.write(line); +}; + +/** + * Wraps a Signale instance so that every call to one of PERSISTED_METHODS is also + * appended to the backend log file, in addition to its normal console output. + * + * @param {Signale} instance + * @param {String} scope + * @returns {Signale} + */ +const withFileSink = (instance, scope) => { + for (const method of PERSISTED_METHODS) { + const original = instance[method].bind(instance); + instance[method] = (...args) => { + writeToFile(method, scope, args); + return original(...args); + }; + } + return instance; +}; + +const createLogger = (scope) => withFileSink(new signale.Signale({ scope, ...opts }), scope); + +const global = createLogger("Global "); +const migrate = createLogger("Migrate "); +const express = createLogger("Express "); +const access = createLogger("Access "); +const nginx = createLogger("Nginx "); +const ssl = createLogger("SSL "); +const certbot = createLogger("Certbot "); +const importer = createLogger("Importer "); +const setup = createLogger("Setup "); +const ipRanges = createLogger("IP Ranges"); +const remoteVersion = createLogger("Remote Version"); const debug = (logger, ...args) => { if (isDebugMode()) { diff --git a/backend/migrations/20190227065017_settings.js b/backend/migrations/20190227065017_settings.js index a6cbe2c99a..471d0b8577 100644 --- a/backend/migrations/20190227065017_settings.js +++ b/backend/migrations/20190227065017_settings.js @@ -13,13 +13,14 @@ const migrateName = "settings"; const up = (knex) => { logger.info(`[${migrateName}] Migrating Up...`); - return knex.schema.createTable('setting', (table) => { - table.string('id').notNull().primary(); - table.string('name', 100).notNull(); - table.string('description', 255).notNull(); - table.string('value', 255).notNull(); - table.json('meta').notNull(); - }) + return knex.schema + .createTable("setting", (table) => { + table.string("id").notNull().primary(); + table.string("name", 100).notNull(); + table.string("description", 255).notNull(); + table.string("value", 255).notNull(); + table.json("meta").notNull(); + }) .then(() => { logger.info(`[${migrateName}] setting Table created`); }); diff --git a/backend/migrations/20251111090000_redirect_auto_scheme.js b/backend/migrations/20251111090000_redirect_auto_scheme.js index 9f5f9d0642..a15f3e3f3c 100644 --- a/backend/migrations/20251111090000_redirect_auto_scheme.js +++ b/backend/migrations/20251111090000_redirect_auto_scheme.js @@ -17,9 +17,7 @@ const up = (knex) => { .table("redirection_host", async (table) => { // change the column default from $scheme to auto await table.string("forward_scheme").notNull().defaultTo("auto").alter(); - await knex('redirection_host') - .where('forward_scheme', '$scheme') - .update({ forward_scheme: 'auto' }); + await knex("redirection_host").where("forward_scheme", "$scheme").update({ forward_scheme: "auto" }); }) .then(() => { logger.info(`[${migrateName}] redirection_host Table altered`); @@ -38,9 +36,7 @@ const down = (knex) => { return knex.schema .table("redirection_host", async (table) => { await table.string("forward_scheme").notNull().defaultTo("$scheme").alter(); - await knex('redirection_host') - .where('forward_scheme', 'auto') - .update({ forward_scheme: '$scheme' }); + await knex("redirection_host").where("forward_scheme", "auto").update({ forward_scheme: "$scheme" }); }) .then(() => { logger.info(`[${migrateName}] redirection_host Table altered`); diff --git a/backend/migrations/20260131163528_trust_forwarded_proto.js b/backend/migrations/20260131163528_trust_forwarded_proto.js index c32c6fb697..24c50e8d4a 100644 --- a/backend/migrations/20260131163528_trust_forwarded_proto.js +++ b/backend/migrations/20260131163528_trust_forwarded_proto.js @@ -11,15 +11,15 @@ const migrateName = "trust_forwarded_proto"; * @returns {Promise} */ const up = (knex) => { - logger.info(`[${migrateName}] Migrating Up...`); + logger.info(`[${migrateName}] Migrating Up...`); - return knex.schema - .alterTable('proxy_host', (table) => { - table.tinyint('trust_forwarded_proto').notNullable().defaultTo(0); - }) - .then(() => { - logger.info(`[${migrateName}] proxy_host Table altered`); - }); + return knex.schema + .alterTable("proxy_host", (table) => { + table.tinyint("trust_forwarded_proto").notNullable().defaultTo(0); + }) + .then(() => { + logger.info(`[${migrateName}] proxy_host Table altered`); + }); }; /** @@ -29,15 +29,15 @@ const up = (knex) => { * @returns {Promise} */ const down = (knex) => { - logger.info(`[${migrateName}] Migrating Down...`); + logger.info(`[${migrateName}] Migrating Down...`); - return knex.schema - .alterTable('proxy_host', (table) => { - table.dropColumn('trust_forwarded_proto'); - }) - .then(() => { - logger.info(`[${migrateName}] proxy_host Table altered`); - }); + return knex.schema + .alterTable("proxy_host", (table) => { + table.dropColumn("trust_forwarded_proto"); + }) + .then(() => { + logger.info(`[${migrateName}] proxy_host Table altered`); + }); }; -export { up, down }; \ No newline at end of file +export { up, down }; diff --git a/backend/models/access_list.js b/backend/models/access_list.js index 427d447d62..192f045b9b 100644 --- a/backend/models/access_list.js +++ b/backend/models/access_list.js @@ -31,6 +31,10 @@ class AccessList extends Model { $parseDatabaseJson(json) { const thisJson = super.$parseDatabaseJson(json); + // Postgres returns COUNT() as a string + if (typeof thisJson.proxy_host_count === "string") { + thisJson.proxy_host_count = Number.parseInt(thisJson.proxy_host_count, 10); + } return convertIntFieldsToBool(thisJson, boolFields); } diff --git a/backend/models/setting.js b/backend/models/setting.js index 56f7dc5aac..1fbef374cc 100644 --- a/backend/models/setting.js +++ b/backend/models/setting.js @@ -7,23 +7,23 @@ import db from "../db.js"; Model.knex(db()); class Setting extends Model { - $beforeInsert () { + $beforeInsert() { // Default for meta - if (typeof this.meta === 'undefined') { + if (typeof this.meta === "undefined") { this.meta = {}; } } - static get name () { - return 'Setting'; + static get name() { + return "Setting"; } - static get tableName () { - return 'setting'; + static get tableName() { + return "setting"; } - static get jsonAttributes () { - return ['meta']; + static get jsonAttributes() { + return ["meta"]; } } diff --git a/backend/models/user_permission.js b/backend/models/user_permission.js index d878471780..cc6eac2cc7 100644 --- a/backend/models/user_permission.js +++ b/backend/models/user_permission.js @@ -8,21 +8,21 @@ import now from "./now_helper.js"; Model.knex(db()); class UserPermission extends Model { - $beforeInsert () { - this.created_on = now(); + $beforeInsert() { + this.created_on = now(); this.modified_on = now(); } - $beforeUpdate () { + $beforeUpdate() { this.modified_on = now(); } - static get name () { - return 'UserPermission'; + static get name() { + return "UserPermission"; } - static get tableName () { - return 'user_permission'; + static get tableName() { + return "user_permission"; } } diff --git a/backend/package.json b/backend/package.json index 80ae74b45e..b8e0ed9fc8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,37 +13,37 @@ "regenerate-config": "node scripts/regenerate-config" }, "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", + "@apidevtools/json-schema-ref-parser": "^16.0.2", "ajv": "^8.20.0", "archiver": "^8.0.0", "batchflow": "^0.4.0", "bcrypt": "^6.0.0", - "better-sqlite3": "^12.10.0", - "body-parser": "^2.2.2", + "better-sqlite3": "^13.0.3", + "body-parser": "^2.3.0", "chalk": "5.6.2", - "compression": "^1.8.1", + "compression": "^1.8.2", "express": "^5.2.1", "express-fileupload": "^1.5.2", "gravatar": "^1.8.2", "jsonwebtoken": "^9.0.3", - "knex": "3.2.10", - "liquidjs": "10.27.0", + "knex": "3.3.0", + "liquidjs": "10.29.0", "lodash": "^4.18.1", - "moment": "^2.30.1", - "mysql2": "^3.22.3", - "node-rsa": "^1.1.1", + "moment": "^2.31.0", + "mysql2": "^3.24.4", + "node-rsa": "^2.0.0", "objection": "3.1.5", - "otplib": "^13.4.0", + "otplib": "^13.5.0", "path": "^0.12.7", - "pg": "^8.21.0", - "proxy-agent": "^8.0.1", + "pg": "^8.23.0", + "proxy-agent": "^8.0.2", "signale": "1.4.0", "sqlite3": "^6.0.1", "temp-write": "^6.0.1" }, "devDependencies": { - "@apidevtools/swagger-parser": "^12.1.0", - "@biomejs/biome": "^2.4.15", + "@apidevtools/swagger-parser": "^13.0.0", + "@biomejs/biome": "^2.5.10", "nodemon": "^3.1.14" }, "signale": { diff --git a/backend/routes/audit-log.js b/backend/routes/audit-log.js index c40b1628d8..54edef6e31 100644 --- a/backend/routes/audit-log.js +++ b/backend/routes/audit-log.js @@ -86,10 +86,7 @@ router }, { event_id: req.params.event_id, - expand: - typeof req.query.expand === "string" - ? req.query.expand.split(",") - : null, + expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, }, ); diff --git a/backend/routes/logs.js b/backend/routes/logs.js new file mode 100644 index 0000000000..9088507b3a --- /dev/null +++ b/backend/routes/logs.js @@ -0,0 +1,106 @@ +import express from "express"; +import internalLogViewer from "../internal/log-viewer.js"; +import jwtdecode from "../lib/express/jwt-decode.js"; +import validator from "../lib/validator/index.js"; +import { debug, express as logger } from "../logger.js"; + +const router = express.Router({ + caseSensitive: true, + strict: true, + mergeParams: true, +}); + +/** + * /api/logs/sources + */ +router + .route("/sources") + .options((_, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/logs/sources + * + * Lists the log sources available for the log viewer + */ + .get(async (req, res, next) => { + try { + const data = await internalLogViewer.listSources(res.locals.access); + res.status(200).send(data); + } catch (err) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); + next(err); + } + }); + +/** + * /api/logs/tail + */ +router + .route("/tail") + .options((_, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/logs/tail + * + * Retrieve the last N lines of a log source + */ + .get(async (req, res, next) => { + try { + const data = await validator( + { + required: ["type"], + additionalProperties: false, + properties: { + type: { + type: "string", + enum: ["system", "letsencrypt", "host"], + }, + host_type: { + anyOf: [{ type: "null" }, { type: "string", enum: ["proxy", "redirection", "dead", "stream"] }], + }, + host_id: { + anyOf: [{ type: "null" }, { type: "integer", minimum: 1 }], + }, + channel: { + anyOf: [{ type: "null" }, { type: "string", enum: ["access", "error"] }], + }, + lines: { + anyOf: [{ type: "null" }, { type: "integer", minimum: 1, maximum: 1000 }], + }, + level: { + anyOf: [ + { type: "null" }, + { type: "string", enum: ["INFO", "WARN", "ERROR", "DEBUG", "SUCCESS", "FATAL", "COMPLETE"] }, + ], + }, + search: { + anyOf: [{ type: "null" }, { type: "string", minLength: 1, maxLength: 200 }], + }, + }, + }, + { + type: req.query.type, + host_type: typeof req.query.host_type === "string" ? req.query.host_type : null, + host_id: typeof req.query.host_id !== "undefined" ? req.query.host_id : null, + channel: typeof req.query.channel === "string" ? req.query.channel : null, + lines: typeof req.query.lines !== "undefined" ? req.query.lines : null, + level: typeof req.query.level === "string" ? req.query.level : null, + search: typeof req.query.search === "string" ? req.query.search : null, + }, + ); + + const result = await internalLogViewer.tail(res.locals.access, data); + res.status(200).send(result); + } catch (err) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); + next(err); + } + }); + +export default router; diff --git a/backend/routes/main.js b/backend/routes/main.js index a308ea6179..2d719bb486 100644 --- a/backend/routes/main.js +++ b/backend/routes/main.js @@ -6,6 +6,7 @@ import pjson from "../package.json" with { type: "json" }; import { isSetup } from "../setup.js"; import auditLogRoutes from "./audit-log.js"; import ciRoutes from "./ci.js"; +import logsRoutes from "./logs.js"; import accessListsRoutes from "./nginx/access_lists.js"; import certificatesHostsRoutes from "./nginx/certificates.js"; import deadHostsRoutes from "./nginx/dead_hosts.js"; @@ -50,6 +51,7 @@ router.use("/schema", schemaRoutes); router.use("/tokens", tokensRoutes); router.use("/users", usersRoutes); router.use("/audit-log", auditLogRoutes); +router.use("/logs", logsRoutes); router.use("/reports", reportsRoutes); router.use("/settings", settingsRoutes); router.use("/version", versionRoutes); diff --git a/backend/routes/nginx/certificates.js b/backend/routes/nginx/certificates.js index 99f429b446..dea8094230 100644 --- a/backend/routes/nginx/certificates.js +++ b/backend/routes/nginx/certificates.js @@ -44,18 +44,11 @@ router }, }, { - expand: - typeof req.query.expand === "string" - ? req.query.expand.split(",") - : null, + expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null, }, ); - const rows = await internalCertificate.getAll( - res.locals.access, - data.expand, - data.query, - ); + const rows = await internalCertificate.getAll(res.locals.access, data.expand, data.query); res.status(200).send(rows); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); @@ -70,15 +63,9 @@ router */ .post(async (req, res, next) => { try { - const payload = await apiValidator( - getValidationSchema("/nginx/certificates", "post"), - req.body, - ); + const payload = await apiValidator(getValidationSchema("/nginx/certificates", "post"), req.body); req.setTimeout(900000); // 15 minutes timeout - const result = await internalCertificate.create( - res.locals.access, - payload, - ); + const result = await internalCertificate.create(res.locals.access, payload); res.status(201).send(result); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); @@ -139,16 +126,10 @@ router */ .post(async (req, res, next) => { try { - const payload = await apiValidator( - getValidationSchema("/nginx/certificates/test-http", "post"), - req.body, - ); + const payload = await apiValidator(getValidationSchema("/nginx/certificates/test-http", "post"), req.body); req.setTimeout(60000); // 1 minute timeout - const result = await internalCertificate.testHttpsChallenge( - res.locals.access, - payload, - ); + const result = await internalCertificate.testHttpsChallenge(res.locals.access, payload); res.status(200).send(result); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); @@ -224,10 +205,7 @@ router }, { certificate_id: req.params.certificate_id, - expand: - typeof req.query.expand === "string" - ? req.query.expand.split(",") - : null, + expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, }, ); const row = await internalCertificate.get(res.locals.access, { diff --git a/backend/routes/nginx/dead_hosts.js b/backend/routes/nginx/dead_hosts.js index 31f7043635..a20df4f5fd 100644 --- a/backend/routes/nginx/dead_hosts.js +++ b/backend/routes/nginx/dead_hosts.js @@ -194,9 +194,11 @@ router /** * POST /api/nginx/dead-hosts/123/disable */ - .post((req, res, next) => { + .post(async (req, res, next) => { try { - const result = internalDeadHost.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }); + const result = await internalDeadHost.disable(res.locals.access, { + id: Number.parseInt(req.params.host_id, 10), + }); res.status(200).send(result); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); diff --git a/backend/routes/nginx/proxy_hosts.js b/backend/routes/nginx/proxy_hosts.js index 7045a195cc..ef62cf835a 100644 --- a/backend/routes/nginx/proxy_hosts.js +++ b/backend/routes/nginx/proxy_hosts.js @@ -1,4 +1,5 @@ import express from "express"; +import fs from "node:fs"; import internalProxyHost from "../../internal/proxy-host.js"; import jwtdecode from "../../lib/express/jwt-decode.js"; import apiValidator from "../../lib/validator/api.js"; @@ -206,4 +207,70 @@ router } }); +/** + * Proxy-host logs + * + * /api/nginx/proxy-hosts/123/logs + */ +router + .route("/:host_id/logs") + .options((_, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/nginx/proxy-hosts/123/logs + * + * Retrieve logs for a specific proxy-host + */ + .get(async (req, res, next) => { + try { + const data = await validator( + { + required: ["host_id"], + additionalProperties: false, + properties: { + host_id: { + $ref: "common#/properties/id", + }, + type: { + type: "string", + enum: ["access", "error"], + }, + }, + }, + { + host_id: req.params.host_id, + type: req.query.type || "access", + }, + ); + + const hostId = Number.parseInt(data.host_id, 10); + const logType = data.type === "error" ? "error" : "access"; + const logFile = `/data/logs/proxy-host-${hostId}_${logType}.log`; + + // Check access permission + await res.locals.access.can("proxy_hosts:get", hostId); + + let logs = ""; + if (fs.existsSync(logFile)) { + const content = fs.readFileSync(logFile, { encoding: "utf8" }); + const lines = content.split("\n"); + // Return last 1000 lines to avoid huge payloads + const maxLines = 1000; + if (lines.length > maxLines) { + logs = lines.slice(-maxLines).join("\n"); + } else { + logs = content; + } + } + + res.status(200).send({ logs }); + } catch (err) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); + next(err); + } + }); + export default router; diff --git a/backend/routes/users.js b/backend/routes/users.js index 7c3da8c1d1..3f972223be 100644 --- a/backend/routes/users.js +++ b/backend/routes/users.js @@ -48,18 +48,11 @@ router }, }, { - expand: - typeof req.query.expand === "string" - ? req.query.expand.split(",") - : null, + expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null, }, ); - const users = await internalUser.getAll( - res.locals.access, - data.expand, - data.query, - ); + const users = await internalUser.getAll(res.locals.access, data.expand, data.query); res.status(200).send(users); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); @@ -95,10 +88,7 @@ router } } - const payload = await apiValidator( - getValidationSchema("/users", "post"), - body, - ); + const payload = await apiValidator(getValidationSchema("/users", "post"), body); const user = await internalUser.create(res.locals.access, payload); res.status(201).send(user); } catch (err) { @@ -169,20 +159,14 @@ router }, { user_id: req.params.user_id, - expand: - typeof req.query.expand === "string" - ? req.query.expand.split(",") - : null, + expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, }, ); const user = await internalUser.get(res.locals.access, { id: data.user_id, expand: data.expand, - omit: internalUser.getUserOmisionsByAccess( - res.locals.access, - data.user_id, - ), + omit: internalUser.getUserOmisionsByAccess(res.locals.access, data.user_id), }); res.status(200).send(user); } catch (err) { @@ -198,10 +182,7 @@ router */ .put(async (req, res, next) => { try { - const payload = await apiValidator( - getValidationSchema("/users/{userID}", "put"), - req.body, - ); + const payload = await apiValidator(getValidationSchema("/users/{userID}", "put"), req.body); payload.id = req.params.user_id; const result = await internalUser.update(res.locals.access, payload); res.status(200).send(result); @@ -248,10 +229,7 @@ router */ .put(async (req, res, next) => { try { - const payload = await apiValidator( - getValidationSchema("/users/{userID}/auth", "put"), - req.body, - ); + const payload = await apiValidator(getValidationSchema("/users/{userID}/auth", "put"), req.body); payload.id = req.params.user_id; const result = await internalUser.setPassword(res.locals.access, payload); res.status(200).send(result); @@ -281,15 +259,9 @@ router */ .put(async (req, res, next) => { try { - const payload = await apiValidator( - getValidationSchema("/users/{userID}/permissions", "put"), - req.body, - ); + const payload = await apiValidator(getValidationSchema("/users/{userID}/permissions", "put"), req.body); payload.id = req.params.user_id; - const result = await internalUser.setPermissions( - res.locals.access, - payload, - ); + const result = await internalUser.setPermissions(res.locals.access, payload); res.status(200).send(result); } catch (err) { debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); @@ -408,10 +380,7 @@ router */ .post(async (req, res, next) => { try { - const { code } = await apiValidator( - getValidationSchema("/users/{userID}/2fa/enable", "post"), - req.body, - ); + const { code } = await apiValidator(getValidationSchema("/users/{userID}/2fa/enable", "post"), req.body); const result = await internal2FA.enable(res.locals.access, req.params.user_id, code); res.status(200).send(result); } catch (err) { diff --git a/backend/schema/components/log-sources-object.json b/backend/schema/components/log-sources-object.json new file mode 100644 index 0000000000..e077f1a0f9 --- /dev/null +++ b/backend/schema/components/log-sources-object.json @@ -0,0 +1,69 @@ +{ + "type": "object", + "description": "Available log sources for the log viewer", + "required": ["system", "letsencrypt", "hosts"], + "additionalProperties": false, + "properties": { + "system": { + "type": "object", + "properties": { + "label": { + "type": "string", + "example": "System" + } + } + }, + "letsencrypt": { + "type": "object", + "properties": { + "label": { + "type": "string", + "example": "Let's Encrypt" + } + } + }, + "hosts": { + "type": "object", + "required": ["proxy", "redirection", "dead", "stream"], + "additionalProperties": false, + "properties": { + "proxy": { + "$ref": "#/$defs/host-option-list" + }, + "redirection": { + "$ref": "#/$defs/host-option-list" + }, + "dead": { + "$ref": "#/$defs/host-option-list" + }, + "stream": { + "$ref": "#/$defs/host-option-list" + } + }, + "example": { + "proxy": [{ "id": 1, "label": "example.com" }], + "redirection": [], + "dead": [], + "stream": [{ "id": 1, "label": "Port 5432 → 10.0.0.5:5432" }] + } + } + }, + "$defs": { + "host-option-list": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "label"], + "properties": { + "id": { + "$ref": "../common.json#/properties/id" + }, + "label": { + "type": "string", + "example": "example.com" + } + } + } + } + } +} diff --git a/backend/schema/components/log-tail-object.json b/backend/schema/components/log-tail-object.json new file mode 100644 index 0000000000..a897f08fcf --- /dev/null +++ b/backend/schema/components/log-tail-object.json @@ -0,0 +1,30 @@ +{ + "type": "object", + "description": "The last N lines of a log source", + "required": ["lines", "size", "truncated", "exists"], + "additionalProperties": false, + "properties": { + "lines": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["2026-01-01T00:00:00.000Z INFO [Global ] Backend PID 1 listening on port 3000 ..."] + }, + "size": { + "type": "integer", + "description": "Size in bytes of the underlying log file", + "example": 4096 + }, + "truncated": { + "type": "boolean", + "description": "True when the file is larger than the maximum amount of data scanned per request", + "example": false + }, + "exists": { + "type": "boolean", + "description": "False when the underlying log file does not exist yet", + "example": true + } + } +} diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json index 3ac6462136..90e6e23bb2 100644 --- a/backend/schema/components/proxy-host-object.json +++ b/backend/schema/components/proxy-host-object.json @@ -124,6 +124,9 @@ }, "advanced_config": { "type": "string" + }, + "access_list_id": { + "$ref": "../common.json#/properties/access_list_id" } } }, @@ -132,7 +135,8 @@ "path": "/app", "forward_scheme": "http", "forward_host": "example.com", - "forward_port": 80 + "forward_port": 80, + "access_list_id": 0 } ] }, diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json index 602073ceca..3a1cd52101 100644 --- a/backend/schema/components/stream-object.json +++ b/backend/schema/components/stream-object.json @@ -44,7 +44,7 @@ }, { "type": "string", - "format": "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$" + "pattern": "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$" }, { "type": "string", diff --git a/backend/schema/paths/logs/sources/get.json b/backend/schema/paths/logs/sources/get.json new file mode 100644 index 0000000000..2556986999 --- /dev/null +++ b/backend/schema/paths/logs/sources/get.json @@ -0,0 +1,36 @@ +{ + "operationId": "getLogSources", + "summary": "Get available log sources", + "tags": ["logs"], + "security": [ + { + "bearerAuth": ["admin"] + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "system": { "label": "System" }, + "letsencrypt": { "label": "Let's Encrypt" }, + "hosts": { + "proxy": [{ "id": 1, "label": "example.com" }], + "redirection": [], + "dead": [], + "stream": [{ "id": 1, "label": "Port 5432 → 10.0.0.5:5432" }] + } + } + } + }, + "schema": { + "$ref": "../../../components/log-sources-object.json" + } + } + } + } + } +} diff --git a/backend/schema/paths/logs/tail/get.json b/backend/schema/paths/logs/tail/get.json new file mode 100644 index 0000000000..2e99ede574 --- /dev/null +++ b/backend/schema/paths/logs/tail/get.json @@ -0,0 +1,100 @@ +{ + "operationId": "getLogTail", + "summary": "Get the last N lines of a log source", + "tags": ["logs"], + "security": [ + { + "bearerAuth": ["admin"] + } + ], + "parameters": [ + { + "in": "query", + "name": "type", + "required": true, + "description": "Which log source to read", + "schema": { + "type": "string", + "enum": ["system", "letsencrypt", "host"] + } + }, + { + "in": "query", + "name": "host_type", + "description": "Required when type=host", + "schema": { + "type": "string", + "enum": ["proxy", "redirection", "dead", "stream"] + } + }, + { + "in": "query", + "name": "host_id", + "description": "Required when type=host", + "schema": { + "type": "integer", + "minimum": 1 + } + }, + { + "in": "query", + "name": "channel", + "description": "Required when type=host - which log file to read (not to be confused with host_type=stream)", + "schema": { + "type": "string", + "enum": ["access", "error"] + } + }, + { + "in": "query", + "name": "lines", + "description": "Number of lines to return from the end of the file", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "default": 200 + } + }, + { + "in": "query", + "name": "level", + "description": "Only applicable to type=system", + "schema": { + "type": "string", + "enum": ["INFO", "WARN", "ERROR", "DEBUG", "SUCCESS", "FATAL", "COMPLETE"] + } + }, + { + "in": "query", + "name": "search", + "description": "Case-insensitive plain-text search", + "schema": { + "type": "string", + "maxLength": 200 + } + } + ], + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "default": { + "value": { + "lines": ["2026-01-01T00:00:00.000Z INFO [Global ] Backend PID 1 listening on port 3000 ..."], + "size": 4096, + "truncated": false, + "exists": true + } + } + }, + "schema": { + "$ref": "../../../components/log-tail-object.json" + } + } + } + } + } +} diff --git a/backend/schema/swagger.json b/backend/schema/swagger.json index 4222f19ddd..fd0dc33f51 100644 --- a/backend/schema/swagger.json +++ b/backend/schema/swagger.json @@ -24,6 +24,10 @@ "name": "audit-log", "description": "Endpoints related to Audit Logs" }, + { + "name": "logs", + "description": "Endpoints for viewing system, Let's Encrypt and per-host logs" + }, { "name": "access-lists", "description": "Endpoints related to Access Lists" @@ -81,6 +85,16 @@ "$ref": "./paths/audit-log/id/get.json" } }, + "/logs/sources": { + "get": { + "$ref": "./paths/logs/sources/get.json" + } + }, + "/logs/tail": { + "get": { + "$ref": "./paths/logs/tail/get.json" + } + }, "/nginx/access-lists": { "get": { "$ref": "./paths/nginx/access-lists/get.json" diff --git a/backend/scripts/regenerate-config b/backend/scripts/regenerate-config index 00f8411310..1965777220 100755 --- a/backend/scripts/regenerate-config +++ b/backend/scripts/regenerate-config @@ -46,7 +46,7 @@ const logIt = (msg, type = "info") => logger[type]( // Let's do it. -const processItems = async (model, type) => { +const processItems = async (model, type, hostType) => { const rows = await model .query() .where("is_deleted", 0) @@ -60,17 +60,17 @@ const processItems = async (model, type) => { for (const row of rows) { if (!DRY_RUN) { logIt(`[${type}] Regenerating config #${row.id}: ${row.domain_names ? row.domain_names.join(", ") : 'port ' + row.incoming_port}`); - await internalNginx.configure(proxyHostModel, "proxy_host", row); + await internalNginx.configure(model, hostType, row); } else { logIt(`[${type}] Skipping generation of config #${row.id}: ${row.domain_names ? row.domain_names.join(", ") : 'port ' + row.incoming_port}`); } } }; -await processItems(proxyHostModel, "Proxy Host"); -await processItems(redirectionHostModel, "Redirection Host"); -await processItems(deadHostModel, "404 Host"); -await processItems(streamModel, "Stream"); +await processItems(proxyHostModel, "Proxy Host", "proxy_host"); +await processItems(redirectionHostModel, "Redirection Host", "redirection_host"); +await processItems(deadHostModel, "404 Host", "dead_host"); +await processItems(streamModel, "Stream", "stream"); logIt("Completed", "success"); process.exit(0); diff --git a/backend/setup.js b/backend/setup.js index 84f42793ea..9e8841e15b 100644 --- a/backend/setup.js +++ b/backend/setup.js @@ -6,11 +6,12 @@ import certificateModel from "./models/certificate.js"; import settingModel from "./models/setting.js"; import userModel from "./models/user.js"; import userPermissionModel from "./models/user_permission.js"; +import fs from "node:fs/promises"; export const isSetup = async () => { const row = await userModel.query().select("id").where("is_deleted", 0).first(); return row?.id > 0; -} +}; /** * Creates a default admin users if one doesn't already exist in the database @@ -44,18 +45,14 @@ const setupDefaultUser = async () => { roles: ["admin"], }; - const user = await userModel - .query() - .insertAndFetch(data); + const user = await userModel.query().insertAndFetch(data); - await authModel - .query() - .insert({ - user_id: user.id, - type: "password", - secret: initialAdminPassword, - meta: {}, - }); + await authModel.query().insert({ + user_id: user.id, + type: "password", + secret: initialAdminPassword, + meta: {}, + }); await userPermissionModel.query().insert({ user_id: user.id, @@ -77,22 +74,16 @@ const setupDefaultUser = async () => { * @returns {Promise} */ const setupDefaultSettings = async () => { - const row = await settingModel - .query() - .select("id") - .where({ id: "default-site" }) - .first(); + const row = await settingModel.query().select("id").where({ id: "default-site" }).first(); if (!row?.id) { - await settingModel - .query() - .insert({ - id: "default-site", - name: "Default Site", - description: "What to show when Nginx is hit with an unknown Host", - value: "congratulations", - meta: {}, - }); + await settingModel.query().insert({ + id: "default-site", + name: "Default Site", + description: "What to show when Nginx is hit with an unknown Host", + value: "congratulations", + meta: {}, + }); logger.info("Default settings added"); } }; @@ -103,14 +94,10 @@ const setupDefaultSettings = async () => { * @returns {Promise} */ const setupCertbotPlugins = async () => { - const certificates = await certificateModel - .query() - .where("is_deleted", 0) - .andWhere("provider", "letsencrypt"); + const certificates = await certificateModel.query().where("is_deleted", 0).andWhere("provider", "letsencrypt"); if (certificates?.length) { const plugins = []; - const promises = []; certificates.map((certificate) => { if (certificate.meta && certificate.meta.dns_challenge === true) { @@ -118,24 +105,23 @@ const setupCertbotPlugins = async () => { plugins.push(certificate.meta.dns_provider); } - // Make sure credentials file exists - const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`; - // Escape single quotes and backslashes - if (typeof certificate.meta.dns_provider_credentials === "string") { - const escapedCredentials = certificate.meta.dns_provider_credentials - .replaceAll("'", "\\'") - .replaceAll("\\", "\\\\"); - const credentials_cmd = `[ -f '${credentials_loc}' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo '${escapedCredentials}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'; }`; - promises.push(utils.exec(credentials_cmd)); - } + // Deliberately does NOT write the DNS credentials file here any more. + // + // It used to, so that a later `certbot renew` would find the path recorded in its + // renewal config. The effect was that every backend restart rewrote a plaintext + // DNS provider API token for every DNS-01 certificate, and left it there. + // + // internalCertificate now writes that file immediately before it runs certbot and + // removes it again afterwards, so there is exactly one writer and the credential + // is on disk only for the length of a certbot run. Recreating the files at boot + // would put every one of them straight back. } return true; }); await installPlugins(plugins); - if (promises.length) { - await Promise.all(promises); + if (plugins.length) { logger.info(`Added Certbot plugins ${plugins.join(", ")}`); } } diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 3a10387b27..d365897ab7 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -5,8 +5,8 @@ {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { - listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %}; - {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %}; + listen {{ incoming_port }} reuseport {%- if certificate %} ssl {%- endif %}; + {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} reuseport {%- if certificate %} ssl {%- endif %}; {%- include "_certificates_stream.conf" %} @@ -23,8 +23,8 @@ server { {% if udp_forwarding == 1 or udp_forwarding == true -%} server { - listen {{ incoming_port }} udp; - {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp; + listen {{ incoming_port }} udp reuseport; + {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp reuseport; proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; diff --git a/backend/yarn.lock b/backend/yarn.lock index 427e834fa1..39efe544ad 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -2,20 +2,20 @@ # yarn lockfile v1 -"@apidevtools/json-schema-ref-parser@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.0.1.tgz#3bc445ed2eddf72bc2f9eb2e295c696bdc5be725" - integrity sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw== +"@apidevtools/json-schema-ref-parser@15.3.6": + version "15.3.6" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.3.6.tgz#9e6360264d90b209eb09f9e4dc9a32316d86f4ea" + integrity sha512-oPFDSviRrreUmCZn09LCD4S9QQa6j7zfEwBM1pkGa/kXY0O4sXsEXn4emLP/Tt6tik2+BtgwKk2eldAeOWZ2Rw== dependencies: - "@types/json-schema" "^7.0.15" - js-yaml "^4.1.0" + js-yaml "^4.2.0" -"@apidevtools/json-schema-ref-parser@^15.3.5": - version "15.3.5" - resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.3.5.tgz#503726178d8d792eea7b195566272aaee6837e2f" - integrity sha512-orNOYXw3hYXxxisXMldjzjBzqqTLBPbwOtHg7ovBPvfBHDue1qM9YJENZ3W2BQuS+7z4ThogMbEzEsov57Itkg== +"@apidevtools/json-schema-ref-parser@^16.0.2": + version "16.0.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-16.0.2.tgz#21f55458a55d1b02bc62f19c731913d8e74976b3" + integrity sha512-oCwWUyRdMtt/hnp6ONPudFZzF7tSqiHy46lLx5VsnsLTacs8TSU558VPAiOueFJ8WddCH30PINWDA8ByxhGHmQ== dependencies: - js-yaml "^4.1.1" + js-yaml "^5.4.1" + undici "^8.10.2" "@apidevtools/openapi-schemas@^2.1.0": version "2.1.0" @@ -27,71 +27,72 @@ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== -"@apidevtools/swagger-parser@^12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-12.1.0.tgz#ef73e5f9e32c2becef6d95b90fb4481b0fec8fe4" - integrity sha512-e5mJoswsnAX0jG+J09xHFYQXb/bUc5S3pLpMxUuRUA2H8T2kni3yEoyz2R3Dltw5f4A6j6rPNMpWTK+iVDFlng== +"@apidevtools/swagger-parser@^13.0.0": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-13.0.0.tgz#a8363c086cc2ae0005b270cfc241f353a741e49c" + integrity sha512-TcvnmBzJD7DBREkc/2qaxMqbKpttOaHhOFsYRYKdYAv6HGY+iNlWY2IUA209C2/NmvL9z8RBZhkrESqvGkjqmw== dependencies: - "@apidevtools/json-schema-ref-parser" "14.0.1" + "@apidevtools/json-schema-ref-parser" "15.3.6" "@apidevtools/openapi-schemas" "^2.1.0" "@apidevtools/swagger-methods" "^3.0.2" + "@types/json-schema" "^7.0.15" ajv "^8.17.1" ajv-draft-04 "^1.0.0" call-me-maybe "^1.0.2" -"@biomejs/biome@^2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.4.15.tgz#cb84ad6eb4235e7230b3c105a825e9bc03399944" - integrity sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw== +"@biomejs/biome@^2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.5.10.tgz#c2a42fc6f9c7d9e12c1f77f63dfb6b5489c497b7" + integrity sha512-WRKXARA3kTuiV5sxqTpobJ/I0MVd4vk3pOL6wnp5az4LntFIhWTj1RWZq3DI9PCEN3lXcqy7p5aqUHzvq8AXyQ== optionalDependencies: - "@biomejs/cli-darwin-arm64" "2.4.15" - "@biomejs/cli-darwin-x64" "2.4.15" - "@biomejs/cli-linux-arm64" "2.4.15" - "@biomejs/cli-linux-arm64-musl" "2.4.15" - "@biomejs/cli-linux-x64" "2.4.15" - "@biomejs/cli-linux-x64-musl" "2.4.15" - "@biomejs/cli-win32-arm64" "2.4.15" - "@biomejs/cli-win32-x64" "2.4.15" - -"@biomejs/cli-darwin-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz#3469daa56ac3ff4f16588a120df706381a96f65c" - integrity sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg== - -"@biomejs/cli-darwin-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz#0697b81089409635da16682ac1e539165c262006" - integrity sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ== - -"@biomejs/cli-linux-arm64-musl@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz#c6af054e3732c361e9ad8c44070f909666b5616f" - integrity sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ== - -"@biomejs/cli-linux-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz#527cef60339649a442d51a9cd129ae9dfe9da926" - integrity sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug== - -"@biomejs/cli-linux-x64-musl@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz#b39292ad106c3d5a612bf3c61ba3119f66833013" - integrity sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w== - -"@biomejs/cli-linux-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz#7360b7f81ff03ec6d9350bedc76b89f783b0945d" - integrity sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g== - -"@biomejs/cli-win32-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz#9542aac679174892a9379267e0c0048f8eee4d9f" - integrity sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w== - -"@biomejs/cli-win32-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz#80288e4eea8f916fc5c876e9a486baadb8de537d" - integrity sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ== + "@biomejs/cli-darwin-arm64" "2.5.10" + "@biomejs/cli-darwin-x64" "2.5.10" + "@biomejs/cli-linux-arm64" "2.5.10" + "@biomejs/cli-linux-arm64-musl" "2.5.10" + "@biomejs/cli-linux-x64" "2.5.10" + "@biomejs/cli-linux-x64-musl" "2.5.10" + "@biomejs/cli-win32-arm64" "2.5.10" + "@biomejs/cli-win32-x64" "2.5.10" + +"@biomejs/cli-darwin-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.10.tgz#f1453a7f2e63f228a34645df1c33962f22a6c2a8" + integrity sha512-ItCrxKK6SXVT6flYs0qIuBd4AA3TTTl4d66Re6YI2FuGZnN85NmuYNzkiTJUyYw8qBLv69L5zTUB6uyWd++h3Q== + +"@biomejs/cli-darwin-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.10.tgz#e21041e7bfab01cd453f609b940bf613713d0e24" + integrity sha512-yLsPU9pAmtChXDu8vhKAzErqe+LeeYuwuUB2FZMkRitsmdodxsYRa9KHrFispsUHzzOu+9HB3nP/TQxyia+Sjw== + +"@biomejs/cli-linux-arm64-musl@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.10.tgz#57fc8aee25c08ca6c14526ccc44e282e7ba96eb6" + integrity sha512-t1QAKZwQJRB4dvgJSgFiQ4BNfNPChg69BNonz854qLVxnjT3UvDzQg9mbkTJRu35ZqU0Rw10A73J8Urgbg2RPw== + +"@biomejs/cli-linux-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.10.tgz#aef789a71e5aa86f5a0e1aff6cb4c1b757ec5be1" + integrity sha512-VG8uQW/86a1roLaIFvtIbEigxIdzdJ190oGyg1tV7VYeQtOS+x10sflk7WbuXgw91EtZX5DlIIIej1YqkNLlcg== + +"@biomejs/cli-linux-x64-musl@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.10.tgz#1aebe9f928dc72dc3c112e60f1211a4d646990c4" + integrity sha512-pgDDqp9JybHm2I0KRgzN6i4+lt8xu4iqxUwLzglUMmOmyRTU1AYBGKzh9sNMOtIjah7xoWvKHlLVetvyifzoiQ== + +"@biomejs/cli-linux-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.10.tgz#a82b414abf5d9668fb035ee50a710bf78a7c5fbf" + integrity sha512-4O6T0eq2heoHZN0a9UX+rWQoxXEBaKf+lRi2hbsGlHneUz9BWXM76nEWMK7Eeq8gzMxR1khQB6BFpAASpeXqGg== + +"@biomejs/cli-win32-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.10.tgz#db671cf67d7040a374e8cdda5aebe73c3f4ffba0" + integrity sha512-pxAbxduPO4xq/Cvgaa2lOrs9BB0hEXmmDqfMNP4ZOffGOkUrD1/QGw9UAMpFQpX2P8MqTIIRuQKcmetum4Oa6A== + +"@biomejs/cli-win32-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.10.tgz#3bdeaf5856f21aec6b6c50a7bca5464b9cda5623" + integrity sha512-M+2dgBsl3lXRiTfgPVc2p3anS4Tocojke4rzFLScZ2Y/wmF+36dRb1iHCLiyGqOzQGyTplZH1HnEYviiAqi3nA== "@isaacs/fs-minipass@^4.0.0": version "4.0.1" @@ -100,60 +101,60 @@ dependencies: minipass "^7.0.4" -"@noble/hashes@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-2.0.1.tgz#fc1a928061d1232b0a52bb754393c37a5216c89e" - integrity sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw== +"@noble/hashes@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-2.3.0.tgz#505fd39c3134a37e67c8c4e6c6049a496154879c" + integrity sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ== -"@otplib/core@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/core/-/core-13.4.0.tgz#14db803de5bd09f7c412eba86c7d193a09d57187" - integrity sha512-JqOGcvZQi2wIkEQo8f3/iAjstavpXy6gouIDMHygjNuH6Q0FjbHOiXMdcE94RwfgDNMABhzwUmvaPsxvgm9NYw== +"@otplib/core@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/core/-/core-13.5.0.tgz#629a7fef5b6394f34ff55213b936223b368796a4" + integrity sha512-2rURdkYkb3BDhMs3j/oCCPTve1ybJ6ruLfLfSe1ZSPV+y6RFTbLfAuT0m0ZCnps88ogkIq9t/+Li/kg5RofQwQ== -"@otplib/hotp@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/hotp/-/hotp-13.4.0.tgz#e12a69cc54c000213e4bf2d92dc9741a6897d3a2" - integrity sha512-MJjE0x06mn2ptymz5qZmQveb+vWFuaIftqE0b5/TZZqUOK7l97cV8lRTmid5BpAQMwJDNLW6RnYxGeCRiNdekw== +"@otplib/hotp@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/hotp/-/hotp-13.5.0.tgz#2832cc6e52f3d037428f094177b4779babe19aa5" + integrity sha512-1EwwAti05CeWJn4xXOVMBK9N6dIJlJw/cQkQyiL9OVlkeS452wAve3ffodi+5IUZdWoF1wxVug38RisdxDqDWw== dependencies: - "@otplib/core" "13.4.0" - "@otplib/uri" "13.4.0" + "@otplib/core" "13.5.0" + "@otplib/uri" "13.5.0" -"@otplib/plugin-base32-scure@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/plugin-base32-scure/-/plugin-base32-scure-13.4.0.tgz#04c3b31075bc733ed3fb54d3335a65813faed0fe" - integrity sha512-/t9YWJmMbB8bF5z8mXrBZc2FXBe8B/3hG5FhWr9K8cFwFhyxScbPysmZe8s1UTzSA6N+s8Uv8aIfCtVXPNjJWw== +"@otplib/plugin-base32-scure@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/plugin-base32-scure/-/plugin-base32-scure-13.5.0.tgz#ba2f329aeea3ed4df3c4e21ce2e9c2e8c9aaed4f" + integrity sha512-3JEIHindUMiIeNL0jXepSAkZ/7IkWq4sPdG9eXK0lrMXZG9RdKu5oz/4tuuTodtsFUPYhKlRMqv5xUvQIkMIaA== dependencies: - "@otplib/core" "13.4.0" - "@scure/base" "^2.0.0" + "@otplib/core" "13.5.0" + "@scure/base" "^2.2.0" -"@otplib/plugin-crypto-noble@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto-noble/-/plugin-crypto-noble-13.4.0.tgz#048c6ad84fd718a2b66f108048aa2f7fd118e5d8" - integrity sha512-KrvE4m7Zv+TT1944HzgqFJWJpKb6AyoxDbvhPStmBqdMlv5Gekb80d66cuFRL08kkPgJ5gXUSb5SFpYeB+bACg== +"@otplib/plugin-crypto-noble@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto-noble/-/plugin-crypto-noble-13.5.0.tgz#820227beb159090a7448ce7245a4e615b5579f0e" + integrity sha512-fihOAGFvc4b8XTKyIK3jifFP2nLrUNc2bOaJ3UkUKJjy1XI2FbHKG0WmOH+jFsPfa6VsOnouCnEmSznDxIe0pA== dependencies: - "@noble/hashes" "^2.0.1" - "@otplib/core" "13.4.0" + "@noble/hashes" "^2.2.0" + "@otplib/core" "13.5.0" -"@otplib/totp@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/totp/-/totp-13.4.0.tgz#f43543435f9ea4c7798913ef8f975462f80fce63" - integrity sha512-dK+vl0f0ekzf6mCENRI9AKS2NJUC7OjI3+X8e7QSnhQ2WM7I+i4PGpb3QxKi5hxjTtwVuoZwXR2CFtXdcRtNdQ== +"@otplib/totp@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/totp/-/totp-13.5.0.tgz#48a60807457726ea34f1d1185f994120652e4468" + integrity sha512-GD9LzQnbHDwXCp79s8AaiA5cJR6luX5fEr9AN32AWx4ooRvllPbMkG80gHSA0jbGCnAIX/ChyOtTZ8tgJHMkSg== dependencies: - "@otplib/core" "13.4.0" - "@otplib/hotp" "13.4.0" - "@otplib/uri" "13.4.0" + "@otplib/core" "13.5.0" + "@otplib/hotp" "13.5.0" + "@otplib/uri" "13.5.0" -"@otplib/uri@13.4.0": - version "13.4.0" - resolved "https://registry.yarnpkg.com/@otplib/uri/-/uri-13.4.0.tgz#23fa0b727bec026bb871afd42e1c3e5ff57bed1d" - integrity sha512-x1ozBa5bPbdZCrrTL/HK21qchiK7jYElTu+0ft22abeEhiLYgH1+SIULvOcVk3CK8YwF4kdcidvkq4ciejucJA== +"@otplib/uri@13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@otplib/uri/-/uri-13.5.0.tgz#d2da470be24f872bb1c24717bcdd2e5c122e3ce3" + integrity sha512-LsL1hqTEgJHY40U2eb/Qp6OR1tKkNGwHQTrqqjIuJj0cawGWkLEmeUFK1MHzWBQ4bgy5IdeB5Et7gIDSAH/CRw== dependencies: - "@otplib/core" "13.4.0" + "@otplib/core" "13.5.0" -"@scure/base@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-2.0.0.tgz#ba6371fddf92c2727e88ad6ab485db6e624f9a98" - integrity sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w== +"@scure/base@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-2.3.0.tgz#fc7acb5b7084c53e4e2537d83fa72cddac7143fd" + integrity sha512-NsG6Y03tY6R5BUis4FdVtHVkur0U6FOzskgs9ZXNl78CUc9fkZ78HmENUle1nSOkCasDmbubmWD9qwB7mm4PZA== "@types/json-schema@^7.0.15": version "7.0.15" @@ -197,17 +198,7 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv@^8.0.0, ajv@^8.17.1: - version "8.18.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.18.0.tgz#8864186b6738d003eb3a933172bb3833e10cefbc" - integrity sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A== - dependencies: - fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - -ajv@^8.20.0: +ajv@^8.0.0, ajv@^8.17.1, ajv@^8.20.0: version "8.20.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.20.0.tgz#304b3636add88ba7d936760dd50ece006dea95f9" integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA== @@ -264,13 +255,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -asn1@^0.2.4: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - ast-types@^0.13.4: version "0.13.4" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" @@ -288,27 +272,59 @@ aws-ssl-profiles@^1.1.2: resolved "https://registry.yarnpkg.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz#157dd77e9f19b1d123678e93f120e6f193022641" integrity sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g== -b4a@^1.6.4: - version "1.8.0" - resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.8.0.tgz#1ca3ba0edc9469aaabef5647e769a83d50180b1a" - integrity sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg== +b4a@^1.6.4, b4a@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.8.1.tgz#7f16334ca80127aeb26064a28841acbf174840a4" + integrity sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw== balanced-match@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.3.tgz#6337a2f23e0604a30481423432f99eac603599f9" - integrity sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g== + version "4.0.4" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +bare-events@^2.5.4, bare-events@^2.7.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.9.1.tgz#5c86616966343bcb03a1b3155feab253eadbf349" + integrity sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg== + +bare-fs@^4.5.5: + version "4.8.0" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.8.0.tgz#8c0f916833ae11e6d9d347f9e0a7f46f7375bb8f" + integrity sha512-fM+MhCvdQhZ7NV6S95a07gPSqjIYKn6mFaXfx266wN3ajZGl/+1AzH+ubkXQ0fFZvOe2nk9VHkzdYkQE5zMV3Q== + dependencies: + bare-events "^2.5.4" + bare-path "^3.0.0" + bare-stream "^2.6.4" + bare-url "^2.2.2" + fast-fifo "^1.3.2" + +bare-path@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.1.1.tgz#d4a207c088609b4663a7556a46a97342398bf7e2" + integrity sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ== + +bare-stream@^2.6.4: + version "2.13.3" + resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.13.3.tgz#f6186c7cbb4bbf53a4560f35e48b16373ba51ce6" + integrity sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ== + dependencies: + b4a "^1.8.1" + streamx "^2.25.0" + teex "^1.0.1" -bare-events@^2.7.0: - version "2.8.2" - resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.8.2.tgz#7b3e10bd8e1fc80daf38bb516921678f566ab89f" - integrity sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ== +bare-url@^2.2.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/bare-url/-/bare-url-2.5.2.tgz#e8dafaefbdb56891a0fbc2b0e1c051296d241cd6" + integrity sha512-L13PCJzKG8RGvx8V1/DdMi12ERhC3tprr7/8a94BxpmnRsFqxh5XZNdhtMxu5HPkRshYOOWRGY8lDP7ZhpG9Cg== + dependencies: + bare-path "^3.0.0" base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -basic-ftp@^5.2.0: +basic-ftp@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.3.1.tgz#3148ee9af43c0522514a4f973fecb1d3cbb6d71e" integrity sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw== @@ -326,13 +342,12 @@ bcrypt@^6.0.0: node-addon-api "^8.3.0" node-gyp-build "^4.8.4" -better-sqlite3@^12.10.0: - version "12.10.0" - resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-12.10.0.tgz#bde622d14a18008583a53bc53501ae98f1a12221" - integrity sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ== +better-sqlite3@^13.0.3: + version "13.0.3" + resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-13.0.3.tgz#b6ea0dc7fff7e28d04d9093e81051d38f7beabe2" + integrity sha512-RbOBxmLBG8uvFUc15X9+9SFemKcQ0WBuISBVkpuiaUB2qblC8UWlHEjdWVoZ8AdhSwmoEgsiXKfopX0CQxaACQ== dependencies: - bindings "^1.5.0" - prebuild-install "^7.1.1" + node-addon-api "^8.0.0" binary-extensions@^2.0.0: version "2.3.0" @@ -360,25 +375,25 @@ blueimp-md5@^2.16.0: resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz#b53feea5498dcb53dc6ec4b823adb84b729c4af0" integrity sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w== -body-parser@^2.2.1, body-parser@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.2.tgz#1a32cdb966beaf68de50a9dfbe5b58f83cb8890c" - integrity sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA== +body-parser@^2.2.1, body-parser@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.3.0.tgz#6d8662f4d8c336028b8ac9aa24251b0ca64ba437" + integrity sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw== dependencies: bytes "^3.1.2" - content-type "^1.0.5" + content-type "^2.0.0" debug "^4.4.3" - http-errors "^2.0.0" - iconv-lite "^0.7.0" + http-errors "^2.0.1" + iconv-lite "^0.7.2" on-finished "^2.4.1" - qs "^6.14.1" - raw-body "^3.0.1" - type-is "^2.0.1" + qs "^6.15.2" + raw-body "^3.0.2" + type-is "^2.1.0" -brace-expansion@^5.0.5: - version "5.0.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.6.tgz#ec68fe0a641a29d8711579caf641d05bae1f2285" - integrity sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g== +brace-expansion@^5.0.8: + version "5.0.9" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.9.tgz#7c72438809b5fa5babf54199a1f1c281a6984fcf" + integrity sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg== dependencies: balanced-match "^4.0.2" @@ -553,29 +568,35 @@ compressible@~2.0.18: dependencies: mime-db ">= 1.43.0 < 2" -compression@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.1.tgz#4a45d909ac16509195a9a28bd91094889c180d79" - integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w== +compression@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.2.tgz#781397127ae2da00c0c5f7c76bda5b2a9b32a49f" + integrity sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ== dependencies: bytes "3.1.2" compressible "~2.0.18" debug "2.6.9" + destroy "1.2.0" negotiator "~0.6.4" on-headers "~1.1.0" safe-buffer "5.2.1" vary "~1.1.2" content-disposition@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b" - integrity sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q== + version "1.1.0" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.1.0.tgz#f3db789c752d45564cc7e9e1e0b31790d4a38e17" + integrity sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g== content-type@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== +content-type@^2.0.0, content-type@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-2.1.0.tgz#d9389c43c0a8cf6a355db464d21e07092a40493a" + integrity sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag== + cookie-signature@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" @@ -661,16 +682,16 @@ degenerator@7.0.1: escodegen "^2.1.0" esprima "^4.0.1" -denque@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" - integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== - depd@^2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + detect-libc@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" @@ -742,9 +763,9 @@ es-errors@^1.3.0: integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" - integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + version "1.1.2" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz#a2d0b373205724dfa525d23b0c3e1b1ca582c99b" + integrity sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw== dependencies: es-errors "^1.3.0" @@ -878,9 +899,9 @@ fast-fifo@^1.2.0, fast-fifo@^1.3.2: integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== fast-uri@^3.0.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.2.tgz#8af3d4fc9d3e71b11572cc2673b514a7d1a8c8ec" - integrity sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ== + version "3.1.7" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.7.tgz#743157d957f3cbb4c65310e033dc2ad4ad7dc60a" + integrity sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg== fdir@^6.5.0: version "6.5.0" @@ -999,12 +1020,12 @@ get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" -get-uri@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-8.0.0.tgz#3ac2e278c4bd8a717be70c8f8f8841e7d6aead93" - integrity sha512-CqtZlMKvfJeY0Zxv8wazDwXmSKmnMnsmNy8j8+wudi8EyG/pMUB1NqHc+Tv1QaNtpYsK9nOYjb7r7Ufu32RPSw== +get-uri@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-8.0.1.tgz#772b1418bf034c2c43ddd6a41af24a4262e135ee" + integrity sha512-/5N/P4Lrh0p/mDwlDRi7Y1+P2o/OyzZI3l6Iz1Ov6XXwwm1y3RlZLuo3gVgML99djrEDtV980bBxSuOeHLk8ww== dependencies: - basic-ftp "^5.2.0" + basic-ftp "^5.3.1" data-uri-to-buffer "8.0.0" debug "^4.3.4" @@ -1055,10 +1076,10 @@ has-symbols@^1.1.0: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== +hasown@^2.0.2, hasown@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== dependencies: function-bind "^1.1.2" @@ -1073,26 +1094,28 @@ http-errors@^2.0.0, http-errors@^2.0.1, http-errors@~2.0.1: statuses "~2.0.2" toidentifier "~1.0.1" -http-proxy-agent@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-9.0.0.tgz#473fe9c2b8ffea87611f8c68dfb9872b835c91d1" - integrity sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA== +http-proxy-agent@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz#fd8b39dcb58ac8046139e5f4ea80de78e8beaf7b" + integrity sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig== dependencies: agent-base "9.0.0" debug "^4.3.4" + proxy-agent-negotiate "1.1.0" -https-proxy-agent@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-9.0.0.tgz#89256adf9dc20926fe43ea1d3ca0feb9e23cc4bd" - integrity sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g== +https-proxy-agent@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz#a9f60f79bc1578c37b166dd7f58b6bcb5c57e44b" + integrity sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA== dependencies: agent-base "9.0.0" debug "^4.3.4" + proxy-agent-negotiate "1.1.0" -iconv-lite@^0.7.0, iconv-lite@^0.7.2, iconv-lite@~0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" - integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== +iconv-lite@^0.7.2, iconv-lite@^0.7.3, iconv-lite@~0.7.0: + version "0.7.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.3.tgz#84ee12f963e7de50bc01a13e160a078b3b0f415f" + integrity sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -1126,10 +1149,10 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -ip-address@^10.0.1: - version "10.2.0" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.2.0.tgz#805fc178b20c518bd4c8548b24fe30892d7f3206" - integrity sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA== +ip-address@^10.1.1: + version "10.5.0" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.5.0.tgz#fcd6d7dfe9e68416b7cb71afe9bc960b3e38c13b" + integrity sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g== ipaddr.js@1.9.1: version "1.9.1" @@ -1149,11 +1172,11 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-core-module@^2.16.1: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + version "2.16.2" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.2.tgz#3e07450a8080ebce3fbf0cac494f4d2ab324e082" + integrity sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA== dependencies: - hasown "^2.0.2" + hasown "^2.0.3" is-extglob@^2.1.1: version "2.1.1" @@ -1202,10 +1225,17 @@ isexe@^4.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-4.0.0.tgz#48f6576af8e87a18feb796b7ed5e2e5903b43dca" integrity sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw== -js-yaml@^4.1.0, js-yaml@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" - integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== +js-yaml@^4.2.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.2.tgz#8e44fb14a2643c59726bb15787b5f1512cb3d3fb" + integrity sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA== + dependencies: + argparse "^2.0.1" + +js-yaml@^5.4.1: + version "5.4.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-5.4.2.tgz#eebc7a57e0bbe1d6b6d9416a72e7463082c7da85" + integrity sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg== dependencies: argparse "^2.0.1" @@ -1252,10 +1282,10 @@ jws@^4.0.1: jwa "^2.0.1" safe-buffer "^5.0.1" -knex@3.2.10: - version "3.2.10" - resolved "https://registry.yarnpkg.com/knex/-/knex-3.2.10.tgz#ca8f77a10851b1e18b26463a6dc995e563c3b165" - integrity sha512-oypTHfrc9i72iyxaUQBKHOxhcr0xM65MPf6FpN02nimsftXwzXprIkLjfXdubvhbu4PMWLp023q8o8CYvHSuZw== +knex@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/knex/-/knex-3.3.0.tgz#451d24d5670939fc4ce54f2269163dbf2627d682" + integrity sha512-LgWl031hNuLv9Lhxdd9093zULa2aNcoP04Bk29e5NidgRcEr/T0rAr2WYi4BhjTiCDoQiRU56meUE5rppLKZzQ== dependencies: colorette "2.0.19" commander "^10.0.0" @@ -1269,7 +1299,7 @@ knex@3.2.10: pg-connection-string "2.6.2" rechoir "^0.8.0" resolve-from "^5.0.0" - tarn "^3.0.2" + tarn "^3.1.0" tildify "2.0.0" lazystream@^1.0.0: @@ -1279,10 +1309,10 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" -liquidjs@10.27.0: - version "10.27.0" - resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-10.27.0.tgz#e31dc4c539e1a26aee46c847b4e60a6ede32564a" - integrity sha512-tw/OA59K7aIBlMKIrKlumr37fiZUheShVHXY8cVctWisgY1p9mc5hreOvlreoS0wTiwlWk14Ya7305c2a/Cg5w== +liquidjs@10.29.0: + version "10.29.0" + resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-10.29.0.tgz#ee061890ccf0da26be377aad4f02bd32da0140d8" + integrity sha512-pCVOhs6FLAR8su3ItJ07diN26t6W5dHQRnmTMy8HPyTFuv1+oSCVJIGp5pGjfQyOZfh50KswvKtMTp6p4JEIdw== dependencies: commander "^10.0.0" @@ -1372,9 +1402,9 @@ math-intrinsics@^1.1.0: integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== media-typer@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" - integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.1.tgz#6f035400dfe3ab9d5607bc77546ce30cc2f9c6b8" + integrity sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ== merge-descriptors@^2.0.0: version "2.0.0" @@ -1399,11 +1429,11 @@ mimic-response@^3.1.0: integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== minimatch@^10.2.1, minimatch@^10.2.2: - version "10.2.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" - integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== + version "10.2.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef" + integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A== dependencies: - brace-expansion "^5.0.5" + brace-expansion "^5.0.8" minimist@^1.2.0, minimist@^1.2.3: version "1.2.8" @@ -1427,10 +1457,10 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -moment@^2.30.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== +moment@^2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.31.0.tgz#6e19184e8005a9dfc61c9351263d4d6ea2ace7aa" + integrity sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw== ms@2.0.0: version "2.0.0" @@ -1447,19 +1477,18 @@ ms@^2.1.1, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mysql2@^3.22.3: - version "3.22.3" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.22.3.tgz#884a36a1171501ef752ba90057dbcde528f322e3" - integrity sha512-uWWxvZSRvRhtBdh2CdcuK83YcOfPdmEeEYB069bAmPnV93QApDGVPuvCQOLjlh7tYHEWdgQPrn6kosDxHBVLkA== +mysql2@^3.24.4: + version "3.24.4" + resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.24.4.tgz#7752de0cf10b1d2984103bdbc60f696c60756f31" + integrity sha512-A2olluVlj0mvgyIRRISMEzXc51m+21mRtcMVjJyIpt2GG98+XrC9m9HzsqcMsX2LcnfccJvY5NB22g8fENBnOA== dependencies: aws-ssl-profiles "^1.1.2" - denque "^2.1.0" generate-function "^2.3.1" - iconv-lite "^0.7.2" + iconv-lite "^0.7.3" long "^5.3.2" lru.min "^1.1.4" named-placeholders "^1.1.6" - sql-escaper "^1.3.3" + sql-escaper "^1.5.1" named-placeholders@^1.1.6: version "1.1.6" @@ -1474,9 +1503,11 @@ napi-build-utils@^2.0.0: integrity sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== negotiator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" - integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + version "1.1.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.1.0.tgz#16e003d0db4ac24fd9df168edf871625deeae3df" + integrity sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg== + dependencies: + content-type "^2.1.0" negotiator@~0.6.4: version "0.6.4" @@ -1484,26 +1515,21 @@ negotiator@~0.6.4: integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== netmask@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + version "2.1.1" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.1.1.tgz#80043d265b53aa521b3bd01e8fcdf353f9e1e81e" + integrity sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA== node-abi@^3.3.0: - version "3.87.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.87.0.tgz#423e28fea5c2f195fddd98acded9938c001ae6dd" - integrity sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ== + version "3.94.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.94.0.tgz#007181ed0d1b56ae9670ea6c084d2bf83538405f" + integrity sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g== dependencies: semver "^7.3.5" -node-addon-api@^8.0.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.7.0.tgz#f64f8413456ecbe900221305a3f883c37666473f" - integrity sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA== - -node-addon-api@^8.3.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.5.0.tgz#c91b2d7682fa457d2e1c388150f0dff9aafb8f3f" - integrity sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A== +node-addon-api@^8.0.0, node-addon-api@^8.3.0: + version "8.9.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.9.2.tgz#db7ac94a13ffd9b55e6cb04584bd5ef8e1d74b18" + integrity sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg== node-gyp-build@^4.8.4: version "4.8.4" @@ -1511,9 +1537,9 @@ node-gyp-build@^4.8.4: integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== node-gyp@12.x: - version "12.3.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-12.3.0.tgz#a0e0d9364779451eaf4148b6f9a7366f98000b3f" - integrity sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg== + version "12.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-12.4.0.tgz#2d017b6ea1ca9294dbbee75be533728f49257024" + integrity sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw== dependencies: env-paths "^2.2.0" exponential-backoff "^3.1.1" @@ -1526,12 +1552,12 @@ node-gyp@12.x: undici "^6.25.0" which "^6.0.0" -node-rsa@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d" - integrity sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw== +node-rsa@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-2.0.0.tgz#f55c99fb3ffef08b24bab414b7d2f24b30d12081" + integrity sha512-7yfzccmBd5rm7pALJf709tPwLL987WvdT7LC/QK5Oxa5S2aabdBPjxRDxhWKkbfCc9/FiC82lwSc+ulGZHH44g== dependencies: - asn1 "^0.2.4" + "@noble/hashes" "^2.2.0" nodemon@^3.1.14: version "3.1.14" @@ -1561,7 +1587,7 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -object-inspect@^1.13.3: +object-inspect@^1.13.3, object-inspect@^1.13.4: version "1.13.4" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== @@ -1594,17 +1620,17 @@ once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -otplib@^13.4.0: - version "13.4.0" - resolved "https://registry.yarnpkg.com/otplib/-/otplib-13.4.0.tgz#5743391a7fe1900cb1ac364af0bbb407a72af76b" - integrity sha512-RUcYcRMCgRWhUE/XabRppXpUwCwaWBNHe5iPXhdvP8wwDGpGpsIf/kxX/ec3zFsOaM1Oq8lEhUqDwk6W7DHkwg== +otplib@^13.5.0: + version "13.5.0" + resolved "https://registry.yarnpkg.com/otplib/-/otplib-13.5.0.tgz#78b5d0d9edf83078d7fe37243bbcdd96d7a65d37" + integrity sha512-RpcC6aq4rANX6MverMuU3pqHVLgMPO7vl6qR8ga7YzoEHlPJknJ58cSVAaf3jBYnasiQVQHXXl2mj/4pYlsVEQ== dependencies: - "@otplib/core" "13.4.0" - "@otplib/hotp" "13.4.0" - "@otplib/plugin-base32-scure" "13.4.0" - "@otplib/plugin-crypto-noble" "13.4.0" - "@otplib/totp" "13.4.0" - "@otplib/uri" "13.4.0" + "@otplib/core" "13.5.0" + "@otplib/hotp" "13.5.0" + "@otplib/plugin-base32-scure" "13.5.0" + "@otplib/plugin-crypto-noble" "13.5.0" + "@otplib/totp" "13.5.0" + "@otplib/uri" "13.5.0" p-limit@^1.1.0: version "1.3.0" @@ -1644,19 +1670,19 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-9.0.1.tgz#9cee1f8b41b00c53418f10824a8a41b3e07587dd" - integrity sha512-3ZOSpLboOlpW4yp8Cuv21KlTULRqyJ5Uuad3wXpSKFrxdNgcHEyoa22GRaZ2UlgCVuR6z+5BiavtYVvbajL/Yw== +pac-proxy-agent@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-9.1.0.tgz#cafd7bb54905de0b6804283cd273eb22028c6abd" + integrity sha512-1aU+1mpj3DrQPfo3gh+3Gap3G5x+axnMx1P/y0ZF2ch7kb2meyOCAH8K2k9d27ROsTE7TnAerzxqF9aon2jqnA== dependencies: agent-base "9.0.0" debug "^4.3.4" - get-uri "8.0.0" - http-proxy-agent "9.0.0" - https-proxy-agent "9.0.0" + get-uri "8.0.1" + http-proxy-agent "9.1.0" + https-proxy-agent "9.1.0" pac-resolver "9.0.1" quickjs-wasi "^2.2.0" - socks-proxy-agent "10.0.0" + socks-proxy-agent "10.1.0" pac-resolver@9.0.1: version "9.0.1" @@ -1717,10 +1743,10 @@ pg-connection-string@2.6.2: resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475" integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA== -pg-connection-string@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.13.0.tgz#8678113465a5af3cc977dcb51eadc847b27aa2de" - integrity sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig== +pg-connection-string@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.14.0.tgz#abc26ee4f37c56c0f3ae0fcf0b0653cc4e1c0fd9" + integrity sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg== pg-int8@1.0.1: version "1.0.1" @@ -1732,10 +1758,10 @@ pg-pool@^3.14.0: resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.14.0.tgz#f35ae4eb846780cad71af24099b3edfa9781ad90" integrity sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw== -pg-protocol@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.14.0.tgz#c1f045b74274b007078c687147141f785f59b8de" - integrity sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA== +pg-protocol@^1.16.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.16.0.tgz#cffb008826561ee9770a8a15dc21f269d731b305" + integrity sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg== pg-types@2.2.0: version "2.2.0" @@ -1748,14 +1774,14 @@ pg-types@2.2.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@^8.21.0: - version "8.21.0" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.21.0.tgz#d7fa2118d960cec5cc7d2b24525f9850dd5932b0" - integrity sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA== +pg@^8.23.0: + version "8.23.0" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.23.0.tgz#5c2026d32bd0cb4fbd9196bac1ecf5ae66607180" + integrity sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg== dependencies: - pg-connection-string "^2.13.0" + pg-connection-string "^2.14.0" pg-pool "^3.14.0" - pg-protocol "^1.14.0" + pg-protocol "^1.16.0" pg-types "2.2.0" pgpass "1.0.5" optionalDependencies: @@ -1774,9 +1800,9 @@ picomatch@^2.0.4, picomatch@^2.2.1: integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== picomatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" - integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== + version "4.0.5" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.5.tgz#51ea57a17d86f605f81039595fbc40ed06a55fab" + integrity sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A== pify@^3.0.0: version "3.0.0" @@ -1813,7 +1839,7 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -prebuild-install@^7.1.1, prebuild-install@^7.1.3: +prebuild-install@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" integrity sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug== @@ -1854,19 +1880,24 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-agent@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-8.0.1.tgz#4819c7b14637c6940424aeed840e9883a378a15d" - integrity sha512-kccqGBqHZXR8onQhY/ganJjoO8QIKKRiFBhPOzbTZK16attzSZ/0XSmp9H7jrRxPKHjhGyx1q32lMPrJ3uLFgA== +proxy-agent-negotiate@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz#de7d37aede9d71e74346125d6f484fac8092b615" + integrity sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ== + +proxy-agent@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-8.0.2.tgz#70737a3b9cdc8bd7a282c9e6ff54a64f5252413c" + integrity sha512-idLLRewuemWd7GH/BDJzGiB0dWGfT2SQs3jy6NtZtGWU9uPTTSdeC1/cdbqLwgzhfv027daGFuXX426e2Eg20A== dependencies: agent-base "9.0.0" debug "^4.3.4" - http-proxy-agent "9.0.0" - https-proxy-agent "9.0.0" + http-proxy-agent "9.1.0" + https-proxy-agent "9.1.0" lru-cache "^7.14.1" - pac-proxy-agent "9.0.1" + pac-proxy-agent "9.1.0" proxy-from-env "^2.0.0" - socks-proxy-agent "10.0.0" + socks-proxy-agent "10.1.0" proxy-from-env@^2.0.0: version "2.1.0" @@ -1879,19 +1910,20 @@ pstree.remy@^1.1.8: integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== pump@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" - integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + version "3.0.4" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.4.tgz#1f313430527fa8b905622ebd22fe1444e757ab3c" + integrity sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA== dependencies: end-of-stream "^1.1.0" once "^1.3.1" -qs@^6.14.0, qs@^6.14.1: - version "6.15.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.2.tgz#fd55426d710403ddccc45e0f9eab16db7727ece9" - integrity sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw== +qs@^6.14.0, qs@^6.15.2: + version "6.16.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.16.0.tgz#c22c723a28a920f3aacdce8289fabd43eccb79fd" + integrity sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA== dependencies: - side-channel "^1.1.0" + es-define-property "^1.0.1" + side-channel "^1.1.1" querystring@0.2.0: version "0.2.0" @@ -1904,11 +1936,11 @@ quickjs-wasi@^2.2.0: integrity sha512-zQxXmQMrEoD3S+jQdYsloq4qAuaxKFHZj6hHqOYGwB2iQZH+q9e/lf5zQPXCKOk0WJuAjzRFbO4KwHIp2D05Iw== range-parser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.3.0.tgz#d7f19be812bb62721472b45d3be219ef09572b47" + integrity sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw== -raw-body@^3.0.1: +raw-body@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.2.tgz#3e3ada5ae5568f9095d84376fd3a49b8fb000a51" integrity sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA== @@ -2003,10 +2035,11 @@ resolve-from@^5.0.0: integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve@^1.20.0: - version "1.22.11" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" - integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + version "1.22.12" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.12.tgz#f5b2a680897c69c238a13cd16b15671f8b73549f" + integrity sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA== dependencies: + es-errors "^1.3.0" is-core-module "^2.16.1" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -2032,15 +2065,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.7.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" - integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + version "7.8.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69" + integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA== send@^1.1.0, send@^1.2.0: version "1.2.1" @@ -2079,13 +2112,13 @@ setprototypeof@~1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -side-channel-list@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" - integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== +side-channel-list@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.1.tgz#c2e0b5a14a540aebee3bbc6c3f8666cc9b509127" + integrity sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w== dependencies: es-errors "^1.3.0" - object-inspect "^1.13.3" + object-inspect "^1.13.4" side-channel-map@^1.0.1: version "1.0.1" @@ -2108,14 +2141,14 @@ side-channel-weakmap@^1.0.2: object-inspect "^1.13.3" side-channel-map "^1.0.1" -side-channel@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" - integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== +side-channel@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.1.tgz#ea02c62e05dc4bea67d4442f0fb71ee192f8e0ab" + integrity sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ== dependencies: es-errors "^1.3.0" - object-inspect "^1.13.3" - side-channel-list "^1.0.0" + object-inspect "^1.13.4" + side-channel-list "^1.0.1" side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" @@ -2154,21 +2187,21 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -socks-proxy-agent@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-10.0.0.tgz#e94a497f890d790a67274c19837c5bbe3f182220" - integrity sha512-pyp2YR3mNxAMu0mGLtzs4g7O3uT4/9sQOLAKcViAkaS9fJWkud7nmaf6ZREFqQEi24IPkBcjfHjXhPTUWjo3uA== +socks-proxy-agent@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-10.1.0.tgz#8eaf7d64ad8752ca43ab04a1a9567be9b7fc40b1" + integrity sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ== dependencies: agent-base "9.0.0" debug "^4.3.4" socks "^2.8.3" socks@^2.8.3: - version "2.8.7" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea" - integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== + version "2.8.9" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.9.tgz#aa5f130ca0f88a43fa44faf4869c50d22aa27752" + integrity sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw== dependencies: - ip-address "^10.0.1" + ip-address "^10.1.1" smart-buffer "^4.2.0" source-map@~0.6.1: @@ -2181,10 +2214,10 @@ split2@^4.1.0: resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== -sql-escaper@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/sql-escaper/-/sql-escaper-1.3.3.tgz#65faf89f048d26bb9a75566b82b5990ddf8a5b7f" - integrity sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw== +sql-escaper@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/sql-escaper/-/sql-escaper-1.5.1.tgz#fbaee511294d1f7da92fb68ca1faee2255839c7b" + integrity sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg== sqlite3@^6.0.1: version "6.0.1" @@ -2208,10 +2241,10 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -streamx@^2.15.0: - version "2.23.0" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.23.0.tgz#7d0f3d00d4a6c5de5728aecd6422b4008d66fd0b" - integrity sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg== +streamx@^2.12.5, streamx@^2.15.0, streamx@^2.25.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.28.0.tgz#035ab56057b7ed2211b51d532e6973f0f99fbf11" + integrity sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw== dependencies: events-universal "^1.0.0" fast-fifo "^1.3.2" @@ -2270,9 +2303,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== tar-fs@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" - integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== + version "2.1.5" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.5.tgz#33e9c29413dce0c58ada7ff77db4e5a30afffe70" + integrity sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw== dependencies: chownr "^1.1.1" mkdirp-classic "^0.5.2" @@ -2291,18 +2324,19 @@ tar-stream@^2.1.4: readable-stream "^3.1.1" tar-stream@^3.0.0: - version "3.1.7" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" - integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + version "3.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.2.0.tgz#0d0064d9b67ea3c9f5abde155e35faab0df37591" + integrity sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg== dependencies: b4a "^1.6.4" + bare-fs "^4.5.5" fast-fifo "^1.2.0" streamx "^2.15.0" tar@^7.5.10, tar@^7.5.4: - version "7.5.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.15.tgz#afe6d1316cddf614a566e3813e42fe01aed46fee" - integrity sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ== + version "7.5.22" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.22.tgz#a696f998136e71487dc3f869a85bba2c67971ba9" + integrity sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA== dependencies: "@isaacs/fs-minipass" "^4.0.0" chownr "^3.0.0" @@ -2310,10 +2344,17 @@ tar@^7.5.10, tar@^7.5.4: minizlib "^3.1.0" yallist "^5.0.0" -tarn@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" - integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== +tarn@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.1.2.tgz#d2922d34a232c8b027605f3873a9c55318ce4f34" + integrity sha512-3RTvqKZcK/17jnJ8rMKFXbyNogywTs1z0gVPPwFsJGX46rkmUHOdIaSQ/aVO1rS7nH+soiXiWk7rvUXxndm8Dg== + +teex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/teex/-/teex-1.0.1.tgz#b8fa7245ef8e8effa8078281946c85ab780a0b12" + integrity sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg== + dependencies: + streamx "^2.12.5" temp-dir@^3.0.0: version "3.0.0" @@ -2342,9 +2383,9 @@ tildify@2.0.0: integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw== tinyglobby@^0.2.12: - version "0.2.16" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.16.tgz#1c3b7eb953fce42b226bc5a1ee06428281aff3d6" - integrity sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg== + version "0.2.17" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" + integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== dependencies: fdir "^6.5.0" picomatch "^4.0.4" @@ -2378,12 +2419,12 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -type-is@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" - integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== +type-is@^2.0.1, type-is@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.1.0.tgz#71d1a7053293582e16ac9f3ebaf1ab9aa49e5570" + integrity sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA== dependencies: - content-type "^1.0.5" + content-type "^2.0.0" media-typer "^1.1.0" mime-types "^3.0.0" @@ -2393,9 +2434,14 @@ undefsafe@^2.0.5: integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== undici@^6.25.0: - version "6.25.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-6.25.0.tgz#8c4efb8c998dc187fc1cfb5dde1ef19a211849fb" - integrity sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg== + version "6.28.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.28.0.tgz#9f0e385744fef5021d6596c5bccd783f61193c1c" + integrity sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA== + +undici@^8.10.2: + version "8.10.2" + resolved "https://registry.yarnpkg.com/undici/-/undici-8.10.2.tgz#960bcb0b43c267f86910ea7ca408ada843a44bc7" + integrity sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ== unpipe@~1.0.0: version "1.0.0" diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 8593fd5ef6..56875fd849 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -25,7 +25,7 @@ RUN curl -sL 'https://taskfile.dev/install.sh' | sh COPY rootfs / COPY scripts/install-s6 /tmp/install-s6 -RUN rm -f /etc/nginx/conf.d/production.conf \ +RUN rm -f /etc/nginx/conf.d/production.conf.template \ && chmod 644 /etc/logrotate.d/nginx-proxy-manager \ && /tmp/install-s6 "${TARGETPLATFORM}" \ && rm -f /tmp/install-s6 \ diff --git a/docker/dev/squid.conf b/docker/dev/squid.conf index cdd749f582..b335f01af1 100644 --- a/docker/dev/squid.conf +++ b/docker/dev/squid.conf @@ -28,6 +28,7 @@ acl SSL_ports port 443 acl Safe_ports port 80 # http acl Safe_ports port 81 acl Safe_ports port 443 # https +acl Safe_ports port 8000 # for CI testing with custom admin port # # Recommended minimum Access Permission configuration: diff --git a/docker/docker-compose.ci.postgres.yml b/docker/docker-compose.ci.postgres.yml index b8c4244668..90245ed399 100644 --- a/docker/docker-compose.ci.postgres.yml +++ b/docker/docker-compose.ci.postgres.yml @@ -3,6 +3,7 @@ services: cypress: environment: CYPRESS_stack: "postgres" + NPM_ADMIN_PORT: 8000 fullstack: environment: @@ -11,11 +12,14 @@ services: DB_POSTGRES_USER: "npm" DB_POSTGRES_PASSWORD: "npmpass" DB_POSTGRES_NAME: "npm" + NPM_ADMIN_PORT: 8000 depends_on: - db-postgres - authentik - authentik-worker - authentik-ldap + expose: + - "8000/tcp" db-postgres: image: postgres:17 diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml index 6130f82e3c..be6f517d3d 100644 --- a/docker/docker-compose.ci.yml +++ b/docker/docker-compose.ci.yml @@ -38,6 +38,16 @@ services: - website2.example.com - website3.example.com + examplesite: + image: "${IMAGE}-examplesite:ci-${BUILD_NUMBER}" + build: + context: ../test/docker + dockerfile: Dockerfile.website + expose: + - "80/tcp" + networks: + - fulltest + stepca: image: nginxproxymanager/testca volumes: @@ -105,6 +115,7 @@ services: environment: HTTP_PROXY: "squid:3128" HTTPS_PROXY: "squid:3128" + NPM_ADMIN_PORT: 81 volumes: - "cypress_logs:/test/results" - "./dev/resolv.conf:/etc/resolv.conf:ro" diff --git a/docker/rootfs/etc/logrotate.d/nginx-proxy-manager b/docker/rootfs/etc/logrotate.d/nginx-proxy-manager index de9772971e..3e42324c77 100644 --- a/docker/rootfs/etc/logrotate.d/nginx-proxy-manager +++ b/docker/rootfs/etc/logrotate.d/nginx-proxy-manager @@ -25,3 +25,13 @@ kill -USR1 `cat /run/nginx/nginx.pid 2>/dev/null` 2>/dev/null || true endscript } + +/data/logs/backend.log { + su npm npm + size 10M + rotate 5 + missingok + notifempty + compress + copytruncate +} diff --git a/docker/rootfs/etc/nginx/conf.d/production.conf b/docker/rootfs/etc/nginx/conf.d/production.conf.template similarity index 89% rename from docker/rootfs/etc/nginx/conf.d/production.conf rename to docker/rootfs/etc/nginx/conf.d/production.conf.template index 877e51dda2..452609bcbc 100644 --- a/docker/rootfs/etc/nginx/conf.d/production.conf +++ b/docker/rootfs/etc/nginx/conf.d/production.conf.template @@ -1,7 +1,7 @@ # Admin Interface server { - listen 81 default; - listen [::]:81 default; + listen {{NPM_ADMIN_PORT}} default; + listen [::]:{{NPM_ADMIN_PORT}} default; server_name nginxproxymanager; root /app/frontend; diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh index d2e62f3bbc..172290eae6 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/00-all.sh @@ -17,6 +17,7 @@ fi . /etc/s6-overlay/s6-rc.d/prepare/20-paths.sh . /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh . /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh +. /etc/s6-overlay/s6-rc.d/prepare/45-admin-port.sh . /etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh . /etc/s6-overlay/s6-rc.d/prepare/60-secrets.sh . /etc/s6-overlay/s6-rc.d/prepare/90-banner.sh diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh index fa94651897..4236c90a2e 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh @@ -46,6 +46,12 @@ for loc in "${locations[@]}"; do chownit "$loc" done +# Ensure the JWT key file is owned by the runtime user, even when the /data +# directory ownership already matches PUID:PGID (chownit skips recursion then) +if [ -f /data/keys.json ]; then + chown "$PUID:$PGID" /data/keys.json +fi + if [ "$(is_true "${SKIP_CERTBOT_OWNERSHIP:-}")" = '1' ]; then log_info 'Skipping ownership change of certbot directories' else diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/45-admin-port.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/45-admin-port.sh new file mode 100644 index 0000000000..3807c7d76c --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/45-admin-port.sh @@ -0,0 +1,30 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +# This command reads the `NPM_ADMIN_PORT` env var and will fall +# back to 81 if this is not set or is not a number. + +set -e + +log_info 'Admin Port ...' + +NPM_ADMIN_PORT="${NPM_ADMIN_PORT:-81}" +# ensure admin port is a number +if ! [[ "$NPM_ADMIN_PORT" =~ ^[0-9]+$ ]]; then + echo "WARNING: NPM_ADMIN_PORT must be a number. Defaulting to 81" >&2 + NPM_ADMIN_PORT=81 +fi + +PRODFILE="/etc/nginx/conf.d/production.conf" +SED_REGEX="s/\{\{NPM_ADMIN_PORT\}\}/${NPM_ADMIN_PORT}/g" + +if is_mounted "$PRODFILE"; then + echo "WARNING: skipping ${PRODFILE} — mounted file" >&2 +elif [ -f "$PRODFILE.template" ]; then + if sed -E "$SED_REGEX" "$PRODFILE.template" > "$PRODFILE" && [ -s "$PRODFILE" ]; then + # success + log_info "Generated ${PRODFILE} from template" + else + log_fatal "Failed to generate ${PRODFILE} from template" + fi +fi diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh index 36387a98dc..e37d11cfa0 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh @@ -8,10 +8,6 @@ set -e log_info 'IPv6 ...' -is_mounted() { - awk -v p="$1" '$5 == p { found=1 } END { exit !found }' /proc/self/mountinfo -} - process_folder () { FILES=$(find "$1" -type f -name "*.conf") SED_REGEX= diff --git a/docker/rootfs/usr/bin/check-health b/docker/rootfs/usr/bin/check-health index bcf5552b39..de23c903b6 100755 --- a/docker/rootfs/usr/bin/check-health +++ b/docker/rootfs/usr/bin/check-health @@ -1,6 +1,6 @@ #!/bin/bash -OK=$(curl --silent http://127.0.0.1:81/api/ | jq --raw-output '.status') +OK=$(curl --silent "http://127.0.0.1:${NPM_ADMIN_PORT:-81}/api/" | jq --raw-output '.status') if [ "$OK" == "OK" ]; then echo "OK" diff --git a/docker/rootfs/usr/bin/common.sh b/docker/rootfs/usr/bin/common.sh index 92bf19d9c6..32d4570444 100644 --- a/docker/rootfs/usr/bin/common.sh +++ b/docker/rootfs/usr/bin/common.sh @@ -70,3 +70,7 @@ is_true () { echo '0' fi } + +is_mounted() { + awk -v p="$1" '$5 == p { found=1 } END { exit !found }' /proc/self/mountinfo +} diff --git a/docker/scripts/install-s6 b/docker/scripts/install-s6 index 5fcb4e09bd..55513fe1e7 100755 --- a/docker/scripts/install-s6 +++ b/docker/scripts/install-s6 @@ -8,7 +8,7 @@ BLUE='\E[1;34m' GREEN='\E[1;32m' RESET='\E[0m' -S6_OVERLAY_VERSION=3.2.1.0 +S6_OVERLAY_VERSION=3.2.3.0 TARGETPLATFORM=${1:-linux/amd64} # Determine the correct binary file for the architecture given diff --git a/docs/src/advanced-config/index.md b/docs/src/advanced-config/index.md index 3ab04ce25b..a93a1a4d09 100644 --- a/docs/src/advanced-config/index.md +++ b/docs/src/advanced-config/index.md @@ -248,3 +248,21 @@ On startup, we generate a resolvers directive for Nginx unless this is defined: In this configuration, all DNS queries performed by Nginx will fall to the `/etc/hosts` file and then the `/etc/resolv.conf`. + + +## Changing the Admin UI port from 81 to something else + +First, add an env var to your docker compose file: +```yml + environment: + NPM_ADMIN_PORT: '8000' +``` + +And you'll probably want to expose that port as well + +```yml + ports: + - '8000:8000' +``` + +Then you'll be able to access admin UI at `http://localhost:8000` diff --git a/docs/yarn.lock b/docs/yarn.lock index c756948271..f8c7568b23 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -952,10 +952,10 @@ mitt@^3.0.1: resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== -nanoid@^3.3.11: - version "3.3.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== +nanoid@^3.3.16: + version "3.3.16" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.16.tgz#a04d8ec4b1f10009d2d533947aefe4293737816c" + integrity sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q== oniguruma-to-es@^3.1.0: version "3.1.1" @@ -977,11 +977,11 @@ picocolors@^1.1.1: integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== postcss@^8.4.43, postcss@^8.5.6: - version "8.5.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.14.tgz#a66c2d7808fadf69ebb5b84a03f8bafd76c4919c" - integrity sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg== + version "8.5.25" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.25.tgz#5012a598eaaa897f21bbe8553be3cb7bd2bd78cb" + integrity sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw== dependencies: - nanoid "^3.3.11" + nanoid "^3.3.16" picocolors "^1.1.1" source-map-js "^1.2.1" diff --git a/frontend/.gitignore b/frontend/.gitignore index a9b91bc1a0..50c1dc047e 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,7 +1,7 @@ src/locale/lang # Logs -logs +/logs/ *.log npm-debug.log* yarn-debug.log* diff --git a/frontend/biome.json b/frontend/biome.json index 13f21e36ba..e84969d2b0 100644 --- a/frontend/biome.json +++ b/frontend/biome.json @@ -1,92 +1,75 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignoreUnknown": false, - "includes": [ - "**/*.ts", - "**/*.tsx", - "**/*.js", - "**/*.jsx", - "!**/dist/**/*" - ] - }, - "formatter": { - "enabled": true, - "indentStyle": "tab", - "indentWidth": 4, - "lineWidth": 120, - "formatWithErrors": true - }, - "assist": { - "actions": { - "source": { - "organizeImports": { - "level": "on", - "options": { - "groups": [ - ":BUN:", - ":NODE:", - [ - "npm:*", - "npm:*/**" - ], - ":PACKAGE_WITH_PROTOCOL:", - ":URL:", - ":PACKAGE:", - [ - "/src/*", - "/src/**" - ], - [ - "/**" - ], - [ - "#*", - "#*/**" - ], - ":PATH:" - ] - } - } - } - } - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "correctness": { - "useUniqueElementIds": "off" - }, - "suspicious": { - "noExplicitAny": "off", - "noArrayIndexKey": "off" - }, - "performance": { - "noDelete": "off" - }, - "nursery": "off", - "a11y": { - "useSemanticElements": "off", - "useValidAnchor": "off" - }, - "style": { - "noParameterAssign": "error", - "useAsConstAssertion": "error", - "useDefaultParameterLast": "error", - "useEnumInitializers": "error", - "useSelfClosingElements": "error", - "useSingleVarDeclarator": "error", - "noUnusedTemplateLiteral": "error", - "useNumberNamespace": "error", - "noInferrableTypes": "error", - "noUselessElse": "error" - } - } - } + "$schema": "https://biomejs.dev/schemas/2.5.10/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "!**/dist/**/*"] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "indentWidth": 4, + "lineWidth": 120, + "formatWithErrors": true + }, + "assist": { + "actions": { + "source": { + "organizeImports": { + "level": "on", + "options": { + "groups": [ + ":BUN:", + ":NODE:", + ["npm:*", "npm:*/**"], + ":PACKAGE_WITH_PROTOCOL:", + ":URL:", + ":PACKAGE:", + ["/src/*", "/src/**"], + ["/**"], + ["#*", "#*/**"], + ":PATH:" + ] + } + } + } + } + }, + "linter": { + "enabled": true, + "rules": { + "preset": "recommended", + "correctness": { + "useUniqueElementIds": "off" + }, + "suspicious": { + "noExplicitAny": "off", + "noArrayIndexKey": "off" + }, + "performance": { + "noDelete": "off" + }, + "nursery": "off", + "a11y": { + "useSemanticElements": "off", + "useValidAnchor": "off" + }, + "style": { + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error" + } + } + } } diff --git a/frontend/check-locales.cjs b/frontend/check-locales.cjs old mode 100755 new mode 100644 index deb418a3ec..251b19c4b4 --- a/frontend/check-locales.cjs +++ b/frontend/check-locales.cjs @@ -29,6 +29,9 @@ const allLocales = [ ["tr", "tr-TR"], ["hu", "hu-HU"], ["no", "no-NO"], + ["uk", "uk-UA"], + ["az", "az-AZ"], + ["fa", "fa-IR"], ]; const ignoreUnused = [/^.*$/]; diff --git a/frontend/package.json b/frontend/package.json index 769a2a7702..e2cc7ee64b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,51 +16,52 @@ "test": "vitest" }, "dependencies": { - "@tabler/core": "^1.4.0", - "@tabler/icons-react": "^3.44.0", - "@tanstack/react-query": "^5.100.14", - "@tanstack/react-table": "^8.21.3", + "@tabler/core": "^1.5.1", + "@tabler/icons-react": "^3.46.0", + "@tanstack/react-query": "^5.102.8", + "@tanstack/react-table": "^9.2.4", "@uiw/react-textarea-code-editor": "^3.1.1", "classnames": "^2.5.1", - "country-flag-icons": "^1.6.17", - "date-fns": "^4.3.0", + "country-flag-icons": "^1.6.20", + "date-fns": "^4.4.0", "ez-modal-react": "^1.0.5", "formik": "^2.4.9", "generate-password-browser": "^1.1.0", "humps": "^2.0.1", - "query-string": "^9.3.1", - "react": "^19.2.6", + "query-string": "^9.5.1", + "react": "^19.3.0", "react-bootstrap": "^2.10.10", - "react-dom": "^19.2.6", - "react-intl": "^10.1.9", + "react-dom": "^19.3.0", + "react-intl": "^10.2.0", "react-markdown": "^10.1.0", - "react-router-dom": "^7.15.1", + "react-qr-code": "^2.2.0", + "react-router-dom": "^7.18.4", "react-select": "^5.10.2", "react-toastify": "^11.1.0", - "rooks": "^9.8.0" + "rooks": "^9.9.0" }, "devDependencies": { - "@biomejs/biome": "^2.4.15", - "@formatjs/cli": "^6.16.3", - "@tanstack/react-query-devtools": "^5.100.14", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", + "@biomejs/biome": "^2.5.10", + "@formatjs/cli": "^6.16.30", + "@tanstack/react-query-devtools": "^5.103.1", + "@testing-library/dom": "^10.4.2", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", "@types/country-flag-icons": "^1.2.2", "@types/humps": "^2.0.6", - "@types/node": "^25.9.1", - "@types/react": "^19.2.15", - "@types/react-dom": "^19.2.3", + "@types/node": "^26.6.2", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", "@types/react-table": "^7.7.20", - "@vitejs/plugin-react": "^6.0.2", - "happy-dom": "^20.9.0", - "postcss": "^8.5.15", + "@vitejs/plugin-react": "^6.1.1", + "happy-dom": "^20.14.5", + "postcss": "^8.5.28", "postcss-simple-vars": "^7.0.1", - "sass": "^1.100.0", - "tmp": "^0.2.6", - "typescript": "6.0.3", - "vite": "^8.0.14", - "vite-plugin-checker": "^0.14.1", - "vitest": "^4.1.7" + "sass": "^1.104.1", + "tmp": "^0.2.7", + "typescript": "7.0.2", + "vite": "^8.3.0", + "vite-plugin-checker": "^0.14.5", + "vitest": "^4.1.11" } } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b6f0bba70d..dfd0c7fe44 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,7 +4,7 @@ import EasyModal from "ez-modal-react"; import { RawIntlProvider } from "react-intl"; import { ToastContainer } from "react-toastify"; import { AuthProvider, LocaleProvider, ThemeProvider } from "src/context"; -import { intl } from "src/locale"; +import { getLocale, intl, isRTLLocale } from "src/locale"; import Router from "src/Router.tsx"; // Create a client @@ -26,7 +26,7 @@ function App() { hideProgressBar={true} newestOnTop={true} closeOnClick={true} - rtl={false} + rtl={isRTLLocale(getLocale())} closeButton={false} /> diff --git a/frontend/src/Router.test.tsx b/frontend/src/Router.test.tsx new file mode 100644 index 0000000000..bd61148073 --- /dev/null +++ b/frontend/src/Router.test.tsx @@ -0,0 +1,79 @@ +import "@testing-library/jest-dom/vitest"; +import { cleanup, render, screen, waitFor } from "@testing-library/react"; +import type { ReactNode } from "react"; +import Router from "src/Router"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +const { authState } = vi.hoisted(() => ({ authState: { authenticated: true } })); + +vi.mock("src/context", () => ({ useAuthState: () => authState })); +vi.mock("src/hooks", () => ({ + useHealth: () => ({ data: { status: "OK", setup: true }, isLoading: false, isError: false }), +})); +vi.mock("src/components", () => ({ + Page: ({ children }: { children: ReactNode }) => children, + SiteContainer: ({ children }: { children: ReactNode }) => children, + SiteHeader: () => null, + SiteMenu: () => null, + SiteFooter: () => null, + LoadingPage: () =>

Loading
, + Unhealthy: () =>
Unhealthy
, + ErrorNotFound: () =>

Not found

, +})); +vi.mock("src/pages/Dashboard", () => ({ default: () =>

Dashboard

})); +vi.mock("src/pages/Login", () => ({ default: () =>

Login

})); +vi.mock("src/pages/Nginx/ProxyHosts", () => ({ default: () =>

Proxy hosts

})); + +describe("Router", () => { + beforeEach(() => { + authState.authenticated = true; + window.history.replaceState(null, "", "/"); + }); + + afterEach(() => { + cleanup(); + vi.restoreAllMocks(); + }); + + it.each(["/login", "/login/", "/login?next=/users#form"])( + "redirects an authenticated visit to %s to the dashboard", + async (path) => { + window.history.replaceState(null, "", path); + const replaceState = vi.spyOn(window.history, "replaceState"); + render(); + + expect(await screen.findByRole("heading", { name: "Dashboard" })).toBeVisible(); + expect(window.location.pathname).toBe("/"); + expect(window.location.search).toBe(""); + expect(window.location.hash).toBe(""); + expect(replaceState).toHaveBeenCalledWith(expect.anything(), "", "/"); + }, + ); + + it("shows the login form when signed out and redirects after sign-in", async () => { + authState.authenticated = false; + window.history.replaceState(null, "", "/login"); + const { rerender } = render(); + + expect(await screen.findByRole("heading", { name: "Login" })).toBeVisible(); + expect(window.location.pathname).toBe("/login"); + + authState.authenticated = true; + rerender(); + + expect(await screen.findByRole("heading", { name: "Dashboard" })).toBeVisible(); + await waitFor(() => expect(window.location.pathname).toBe("/")); + }); + + it.each([ + ["/", "Dashboard"], + ["/nginx/proxy", "Proxy hosts"], + ["/unknown", "Not found"], + ])("preserves the existing route for %s", async (path, heading) => { + window.history.replaceState(null, "", path); + render(); + + expect(await screen.findByRole("heading", { name: heading })).toBeVisible(); + expect(window.location.pathname).toBe(path); + }); +}); diff --git a/frontend/src/Router.tsx b/frontend/src/Router.tsx index 6aa8f0894f..dc7556509e 100644 --- a/frontend/src/Router.tsx +++ b/frontend/src/Router.tsx @@ -1,5 +1,5 @@ import { lazy, Suspense } from "react"; -import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom"; import { ErrorNotFound, LoadingPage, @@ -20,6 +20,7 @@ const Settings = lazy(() => import("src/pages/Settings")); const Certificates = lazy(() => import("src/pages/Certificates")); const Access = lazy(() => import("src/pages/Access")); const AuditLog = lazy(() => import("src/pages/AuditLog")); +const Logs = lazy(() => import("src/pages/Logs")); const Users = lazy(() => import("src/pages/Users")); const ProxyHosts = lazy(() => import("src/pages/Nginx/ProxyHosts")); const RedirectionHosts = lazy(() => import("src/pages/Nginx/RedirectionHosts")); @@ -61,9 +62,11 @@ function Router() { }> } /> + } /> } /> } /> } /> + } /> } /> } /> } /> diff --git a/frontend/src/api/backend/getLogSources.ts b/frontend/src/api/backend/getLogSources.ts new file mode 100644 index 0000000000..4bec700024 --- /dev/null +++ b/frontend/src/api/backend/getLogSources.ts @@ -0,0 +1,8 @@ +import * as api from "./base"; +import type { LogSources } from "./models"; + +export async function getLogSources(): Promise { + return await api.get({ + url: "/logs/sources", + }); +} diff --git a/frontend/src/api/backend/getLogTail.ts b/frontend/src/api/backend/getLogTail.ts new file mode 100644 index 0000000000..899282b326 --- /dev/null +++ b/frontend/src/api/backend/getLogTail.ts @@ -0,0 +1,19 @@ +import * as api from "./base"; +import type { LogChannel, LogHostType, LogSourceType, LogTail } from "./models"; + +export interface GetLogTailParams { + type: LogSourceType; + hostType?: LogHostType; + hostId?: number; + channel?: LogChannel; + lines?: number; + level?: string; + search?: string; +} + +export async function getLogTail(params: GetLogTailParams): Promise { + return await api.get({ + url: "/logs/tail", + params: { ...params }, + }); +} diff --git a/frontend/src/api/backend/getProxyHostLogs.ts b/frontend/src/api/backend/getProxyHostLogs.ts new file mode 100644 index 0000000000..91944c9d72 --- /dev/null +++ b/frontend/src/api/backend/getProxyHostLogs.ts @@ -0,0 +1,8 @@ +import * as api from "./base"; + +export async function getProxyHostLogs(id: number, type: "access" | "error" = "access"): Promise<{ logs: string }> { + return await api.get({ + url: `/nginx/proxy-hosts/${id}/logs`, + params: { type }, + }); +} diff --git a/frontend/src/api/backend/index.ts b/frontend/src/api/backend/index.ts index 40cb4142fc..ff6e420684 100644 --- a/frontend/src/api/backend/index.ts +++ b/frontend/src/api/backend/index.ts @@ -26,7 +26,10 @@ export * from "./getDeadHost"; export * from "./getDeadHosts"; export * from "./getHealth"; export * from "./getHostsReport"; +export * from "./getLogSources"; +export * from "./getLogTail"; export * from "./getProxyHost"; +export * from "./getProxyHostLogs"; export * from "./getProxyHosts"; export * from "./getRedirectionHost"; export * from "./getRedirectionHosts"; diff --git a/frontend/src/api/backend/models.ts b/frontend/src/api/backend/models.ts index 2ae0b08348..96c1b8a488 100644 --- a/frontend/src/api/backend/models.ts +++ b/frontend/src/api/backend/models.ts @@ -44,6 +44,30 @@ export interface AuditLog { user?: User; } +export type LogSourceType = "system" | "letsencrypt" | "host"; +export type LogHostType = "proxy" | "redirection" | "dead" | "stream"; +// Which of the two files nginx writes per host - named "channel", not "stream", +// to avoid confusion with the "stream" LogHostType (TCP/UDP stream hosts). +export type LogChannel = "access" | "error"; + +export interface LogHostOption { + id: number; + label: string; +} + +export interface LogSources { + system: { label: string }; + letsencrypt: { label: string }; + hosts: Record; +} + +export interface LogTail { + lines: string[]; + size: number; + truncated: boolean; + exists: boolean; +} + export interface AccessList { id?: number; createdOn?: string; @@ -103,6 +127,8 @@ export interface ProxyLocation { forwardScheme: string; forwardHost: string; forwardPort: number; + accessListId?: number; + accessList?: AccessList; } export interface ProxyHost { diff --git a/frontend/src/components/EmptyData.tsx b/frontend/src/components/EmptyData.tsx index 46a9664c2f..104c8a3611 100644 --- a/frontend/src/components/EmptyData.tsx +++ b/frontend/src/components/EmptyData.tsx @@ -1,12 +1,13 @@ -import type { Table as ReactTable } from "@tanstack/react-table"; +import type { Table as ReactTable, RowData } from "@tanstack/react-table"; import cn from "classnames"; import type { ReactNode } from "react"; import { Button, HasPermission } from "src/components"; +import type { Features } from "src/components/Table/features"; import { T } from "src/locale"; import { type ADMIN, MANAGE, type Permission, type Section } from "src/modules/Permissions"; -interface Props { - tableInstance: ReactTable; +interface Props { + tableInstance: ReactTable; onNew?: () => void; isFiltered?: boolean; object: string; @@ -16,7 +17,7 @@ interface Props { permissionSection?: Section | typeof ADMIN; permission?: Permission; } -function EmptyData({ +function EmptyData({ tableInstance, onNew, isFiltered, @@ -26,7 +27,7 @@ function EmptyData({ customAddBtn, permissionSection, permission, -}: Props) { +}: Props) { return ( diff --git a/frontend/src/components/Form/AccessClientFields.tsx b/frontend/src/components/Form/AccessClientFields.tsx index 9dda8c3de0..bac4458409 100644 --- a/frontend/src/components/Form/AccessClientFields.tsx +++ b/frontend/src/components/Form/AccessClientFields.tsx @@ -65,8 +65,12 @@ export function AccessClientFields({ initialValues, name = "clients" }: Props) { value={client.directive} onChange={(e) => handleChange(idx, "directive", e.target.value)} > - - + + ))} @@ -112,7 +113,9 @@ export function AccessClientFields({ initialValues, name = "clients" }: Props) { value="deny" disabled > - + void; + // When set, the 0 option inherits the host's access list instead of being public + inheritHost?: boolean; } -export function AccessField({ name = "accessListId", label = "access-list", id = "accessListId" }: Props) { +export function AccessField({ + name = "accessListId", + label = "access-list", + id = "accessListId", + onFormChange, + inheritHost = false, +}: Props) { const { locale } = useLocaleState(); const { isLoading, isError, error, data } = useAccessLists(["owner", "items", "clients"]); const { setFieldValue } = useFormikContext(); const handleChange = (newValue: any, _actionMeta: ActionMeta) => { setFieldValue(name, newValue?.value); + if (onFormChange) { + onFormChange(newValue?.value ?? 0); + } }; const options: AccessOption[] = @@ -56,13 +68,22 @@ export function AccessField({ name = "accessListId", label = "access-list", id = icon: , })) || []; - // Public option - options?.unshift({ - value: 0, - label: intl.formatMessage({ id: "access-list.public" }), - subLabel: intl.formatMessage({ id: "access-list.public.subtitle" }), - icon: , - }); + // Public or inherit option + options?.unshift( + inheritHost + ? { + value: 0, + label: intl.formatMessage({ id: "access-list.inherit" }), + subLabel: intl.formatMessage({ id: "access-list.inherit.subtitle" }), + icon: , + } + : { + value: 0, + label: intl.formatMessage({ id: "access-list.public" }), + subLabel: intl.formatMessage({ id: "access-list.public.subtitle" }), + icon: , + }, + ); return ( diff --git a/frontend/src/components/Form/BasicAuthFields.tsx b/frontend/src/components/Form/BasicAuthFields.tsx index c47d96da42..d8d33d1595 100644 --- a/frontend/src/components/Form/BasicAuthFields.tsx +++ b/frontend/src/components/Form/BasicAuthFields.tsx @@ -82,16 +82,13 @@ export function BasicAuthFields({ initialValues, name = "items" }: Props) { /> ))} diff --git a/frontend/src/components/Form/LocationsFields.module.css b/frontend/src/components/Form/LocationsFields.module.css index 4b48ef3cb9..9551e0d4ef 100644 --- a/frontend/src/components/Form/LocationsFields.module.css +++ b/frontend/src/components/Form/LocationsFields.module.css @@ -1,3 +1,51 @@ +/* card-active points --tblr-card-border-color at --tblr-primary, which both the + card outline and the card header's bottom border are drawn from. Tabler's + stylesheet is loaded after this one, so the override needs !important. */ .locationCard { - border-color: light-dark(var(--tblr-gray-200), var(--tblr-gray-700)) !important; + --tblr-card-border-color: light-dark(var(--tblr-gray-200), var(--tblr-gray-700)) !important; +} + +.filter { + max-width: 20rem; +} + +/* The header is a plain toggle rather than a button-styled control, so that a + list of collapsed locations reads as rows instead of a stack of buttons. */ +.toggle { + display: flex; + flex: 1 1 auto; + align-self: stretch; + align-items: center; + min-width: 0; + padding: 0; + color: inherit; + text-align: left; + background: transparent; + border: 0; +} + +.toggle:focus-visible { + outline: 2px solid var(--tblr-primary); + outline-offset: -2px; +} + +/* Keeps the marker on one line next to the delete button, and lets it drop out + of the way before the path does when the row runs out of room. */ +.marker { + display: flex; + flex: 0 1 auto; + align-items: center; + overflow: hidden; + white-space: nowrap; +} + +.path { + font-weight: 500; + white-space: nowrap; +} + +.summary { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } diff --git a/frontend/src/components/Form/LocationsFields.tsx b/frontend/src/components/Form/LocationsFields.tsx index 4240b1f986..a0f64c2393 100644 --- a/frontend/src/components/Form/LocationsFields.tsx +++ b/frontend/src/components/Form/LocationsFields.tsx @@ -1,20 +1,44 @@ -import { IconSettings } from "@tabler/icons-react"; +import { + IconChevronDown, + IconChevronRight, + IconPlus, + IconSearch, + IconSettings, + IconTrash, + IconX, +} from "@tabler/icons-react"; import CodeEditor from "@uiw/react-textarea-code-editor"; import cn from "classnames"; import { useFormikContext } from "formik"; -import { useState } from "react"; +import { useRef, useState } from "react"; import type { ProxyLocation } from "src/api/backend"; import { intl, T } from "src/locale"; +import { AccessField } from "./AccessField"; import styles from "./LocationsFields.module.css"; +// Below this many locations the list is short enough to scan by eye, and the +// filter would only take up space. +const FILTER_THRESHOLD = 5; + +// Locations are identified by a client-side id rather than their array index, +// so that expanded/advanced state stays with the right row when one is removed. +interface Row { + id: number; + value: ProxyLocation; +} + interface Props { initialValues: ProxyLocation[]; name?: string; } export function LocationsFields({ initialValues, name = "locations" }: Props) { - const [values, setValues] = useState(initialValues || []); + const [rows, setRows] = useState(() => (initialValues || []).map((value, id) => ({ id, value }))); const { setFieldValue } = useFormikContext(); + const [expanded, setExpanded] = useState([]); const [advVisible, setAdvVisible] = useState([]); + const [filter, setFilter] = useState(""); + const nextId = useRef(rows.length); + const scrollToId = useRef(null); const blankItem: ProxyLocation = { path: "", @@ -22,34 +46,71 @@ export function LocationsFields({ initialValues, name = "locations" }: Props) { forwardScheme: "http", forwardHost: "", forwardPort: 80, + accessListId: 0, + }; + + const toggleExpanded = (id: number) => { + setExpanded(expanded.includes(id) ? expanded.filter((i) => i !== id) : [...expanded, id]); }; - const toggleAdvVisible = (idx: number) => { - setAdvVisible(advVisible.includes(idx) ? advVisible.filter((i) => i !== idx) : [...advVisible, idx]); + const toggleAdvVisible = (id: number) => { + setAdvVisible(advVisible.includes(id) ? advVisible.filter((i) => i !== id) : [...advVisible, id]); }; const handleAdd = () => { - setValues([...values, blankItem]); + const id = nextId.current++; + setRows([...rows, { id, value: blankItem }]); + // A new location starts empty, so open it and make sure an active filter + // doesn't hide the row that was just added. + setExpanded([...expanded, id]); + setFilter(""); + scrollToId.current = id; }; - const handleRemove = (idx: number) => { - const newValues = values.filter((_: ProxyLocation, i: number) => i !== idx); - setValues(newValues); - setFormField(newValues); + const handleRemove = (id: number) => { + const newRows = rows.filter((r: Row) => r.id !== id); + setRows(newRows); + setExpanded(expanded.filter((i) => i !== id)); + setAdvVisible(advVisible.filter((i) => i !== id)); + setFormField(newRows); }; - const handleChange = (idx: number, field: string, fieldValue: string) => { - const newValues = values.map((v: ProxyLocation, i: number) => (i === idx ? { ...v, [field]: fieldValue } : v)); - setValues(newValues); - setFormField(newValues); + const handleChange = (id: number, field: string, fieldValue: string) => { + const newRows = rows.map((r: Row) => (r.id === id ? { ...r, value: { ...r.value, [field]: fieldValue } } : r)); + setRows(newRows); + setFormField(newRows); }; - const setFormField = (newValues: ProxyLocation[]) => { - const filtered = newValues.filter((v: ProxyLocation) => v?.path?.trim() !== ""); + const handleAccessListChange = (id: number, accessListId: number) => { + const newRows = rows.map((r: Row) => (r.id === id ? { ...r, value: { ...r.value, accessListId } } : r)); + setRows(newRows); + setFormField(newRows); + }; + + const setFormField = (newRows: Row[]) => { + const filtered = newRows.map((r: Row) => r.value).filter((v: ProxyLocation) => v?.path?.trim() !== ""); setFieldValue(name, filtered); }; - if (values.length === 0) { + const forwardSummary = (item: ProxyLocation) => { + if (!item.forwardHost) { + return ""; + } + return `${item.forwardScheme}://${item.forwardHost}${item.forwardPort ? `:${item.forwardPort}` : ""}`; + }; + + // Matches the path as well as the destination, so a location can be found by + // the host or port it forwards to and not just by its path. + const matchesFilter = (item: ProxyLocation, query: string) => + [item.path, item.forwardScheme, item.forwardHost, item.forwardPort, forwardSummary(item)] + .join(" ") + .toLowerCase() + .includes(query); + + const query = filter.trim().toLowerCase(); + const visibleRows = query ? rows.filter((r: Row) => matchesFilter(r.value, query)) : rows; + + if (rows.length === 0) { return (
+ ) : null} +
+ )} + + + {visibleRows.length === 0 ? ( +
+ +
+ ) : ( + visibleRows.map((row: Row) => { + const item = row.value; + const isOpen = expanded.includes(row.id); + const bodyId = `location-body-${row.id}`; + return ( +
{ + if (node && scrollToId.current === row.id) { + scrollToId.current = null; + node.scrollIntoView({ block: "nearest" }); + } + }} + className={cn("card", "card-active", "mb-2", styles.locationCard)} + > +
-
-
-
-
-
- - -
-
-
-
- - handleChange(idx, "forwardHost", e.target.value)} - /> -
+ + + ) : null} +
-
-
- - handleChange(idx, "forwardPort", e.target.value)} + {isOpen && ( +
+
+
+
+ Location + handleChange(row.id, "path", e.target.value)} + /> +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ + + handleChange(row.id, "forwardHost", e.target.value) + } + /> +
+
+
+
+ + + handleChange(row.id, "forwardPort", e.target.value) + } + /> +
+
+
+ handleAccessListChange(row.id, value)} + inheritHost /> + {advVisible.includes(row.id) && ( +
+ handleChange(row.id, "advancedConfig", e.target.value)} + style={{ + fontFamily: + "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace", + borderRadius: "0.3rem", + minHeight: "170px", + }} + /> +
+ )}
-
+ )}
- {advVisible.includes(idx) && ( -
- handleChange(idx, "advancedConfig", e.target.value)} - style={{ - fontFamily: - "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace", - borderRadius: "0.3rem", - minHeight: "170px", - }} - /> -
- )} - -
- - ))} -
- -
+ ); + }) + )} ); } diff --git a/frontend/src/components/Form/SSLOptionsFields.tsx b/frontend/src/components/Form/SSLOptionsFields.tsx index ecf23d26f1..ebfe38a65d 100644 --- a/frontend/src/components/Form/SSLOptionsFields.tsx +++ b/frontend/src/components/Form/SSLOptionsFields.tsx @@ -10,7 +10,13 @@ interface Props { requireDomainNames?: boolean; // used for streams color?: string; } -export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDNSForNew, requireDomainNames, color = "bg-cyan" }: Props) { +export function SSLOptionsFields({ + forHttp = true, + forProxyHost = false, + forceDNSForNew, + requireDomainNames, + color = "bg-cyan", +}: Props) { const { values, setFieldValue } = useFormikContext(); const v: any = values || {}; @@ -116,10 +122,12 @@ export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDN ); - const getHttpAdvancedOptions = () =>( + const getHttpAdvancedOptions = () => (
- + + +
diff --git a/frontend/src/components/SiteHeader.tsx b/frontend/src/components/SiteHeader.tsx index f00d38d6ed..bf28640a0a 100644 --- a/frontend/src/components/SiteHeader.tsx +++ b/frontend/src/components/SiteHeader.tsx @@ -72,7 +72,10 @@ export function SiteHeader() {
{/* biome-ignore lint/a11y/noStaticElementInteractions lint/a11y/useKeyWithClickEvents: This div is not interactive. */} -
e.stopPropagation()}> +
e.stopPropagation()} + >
{currentUser?.nickname}
diff --git a/frontend/src/components/SiteMenu.tsx b/frontend/src/components/SiteMenu.tsx index 265150bb54..c7274751ae 100644 --- a/frontend/src/components/SiteMenu.tsx +++ b/frontend/src/components/SiteMenu.tsx @@ -1,6 +1,7 @@ import { IconBook, IconDeviceDesktop, + IconFileText, IconHome, IconLock, IconSettings, @@ -95,6 +96,12 @@ const menuItems: MenuItem[] = [ label: "auditlogs", permissionSection: ADMIN, }, + { + to: "/logs", + icon: IconFileText, + label: "logs", + permissionSection: ADMIN, + }, { to: "/settings", icon: IconSettings, @@ -143,7 +150,6 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => { className="nav-link dropdown-toggle" href={item.to} data-bs-toggle="dropdown" - data-bs-auto-close="outside" aria-expanded="false" role="button" > @@ -176,13 +182,14 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => { }; export function SiteMenu() { - const closeMenu = () => setTimeout(() => { - const navbarToggler = document.querySelector(".navbar-toggler"); - const navbarMenu = document.querySelector("#navbar-menu"); - if (navbarToggler && navbarMenu?.classList.contains("show")) { - navbarToggler.click(); - } - }, 300); + const closeMenu = () => + setTimeout(() => { + const navbarToggler = document.querySelector(".navbar-toggler"); + const navbarMenu = document.querySelector("#navbar-menu"); + if (navbarToggler && navbarMenu?.classList.contains("show")) { + navbarToggler.click(); + } + }, 300); return (
diff --git a/frontend/src/components/Table/EmptyRow.tsx b/frontend/src/components/Table/EmptyRow.tsx index 2daee952ac..ada39e3e16 100644 --- a/frontend/src/components/Table/EmptyRow.tsx +++ b/frontend/src/components/Table/EmptyRow.tsx @@ -1,9 +1,10 @@ -import type { Table as ReactTable } from "@tanstack/react-table"; +import type { Table as ReactTable, RowData } from "@tanstack/react-table"; +import type { Features } from "./features"; -interface Props { - tableInstance: ReactTable; +interface Props { + tableInstance: ReactTable; } -function EmptyRow({ tableInstance }: Props) { +function EmptyRow({ tableInstance }: Props) { return ( diff --git a/frontend/src/components/Table/TableBody.tsx b/frontend/src/components/Table/TableBody.tsx index d8fe9bf3a4..a3114196b8 100644 --- a/frontend/src/components/Table/TableBody.tsx +++ b/frontend/src/components/Table/TableBody.tsx @@ -1,8 +1,8 @@ -import { flexRender } from "@tanstack/react-table"; +import { flexRender, type RowData } from "@tanstack/react-table"; import type { TableLayoutProps } from "src/components"; import { EmptyRow } from "./EmptyRow"; -function TableBody(props: TableLayoutProps) { +function TableBody(props: TableLayoutProps) { const { tableInstance, extraStyles, emptyState } = props; const rows = tableInstance.getRowModel().rows; diff --git a/frontend/src/components/Table/TableHeader.tsx b/frontend/src/components/Table/TableHeader.tsx index dd409d59d8..f656c4656e 100644 --- a/frontend/src/components/Table/TableHeader.tsx +++ b/frontend/src/components/Table/TableHeader.tsx @@ -1,8 +1,8 @@ import { IconArrowsSort, IconChevronDown, IconChevronUp } from "@tabler/icons-react"; -import { flexRender } from "@tanstack/react-table"; +import { flexRender, type RowData } from "@tanstack/react-table"; import type { TableLayoutProps } from "src/components"; -function TableHeader(props: TableLayoutProps) { +function TableHeader(props: TableLayoutProps) { const { tableInstance } = props; const headerGroups = tableInstance.getHeaderGroups(); diff --git a/frontend/src/components/Table/TableHelpers.ts b/frontend/src/components/Table/TableHelpers.ts index 0df329c804..a6302e09bf 100644 --- a/frontend/src/components/Table/TableHelpers.ts +++ b/frontend/src/components/Table/TableHelpers.ts @@ -61,4 +61,4 @@ const tableEventReducer = (state: any, { type, payload }: any) => { } }; -export { tableEvents, tableEventReducer }; +export { tableEventReducer, tableEvents }; diff --git a/frontend/src/components/Table/TableLayout.tsx b/frontend/src/components/Table/TableLayout.tsx index 630340919d..5db64bafc0 100644 --- a/frontend/src/components/Table/TableLayout.tsx +++ b/frontend/src/components/Table/TableLayout.tsx @@ -1,15 +1,16 @@ -import type { Table as ReactTable } from "@tanstack/react-table"; +import type { Table as ReactTable, RowData } from "@tanstack/react-table"; +import type { Features } from "./features"; import { TableBody } from "./TableBody"; import { TableHeader } from "./TableHeader"; -interface TableLayoutProps { - tableInstance: ReactTable; +interface TableLayoutProps { + tableInstance: ReactTable; emptyState?: React.ReactNode; extraStyles?: { row: (rowData: TFields) => any | undefined; }; } -function TableLayout(props: TableLayoutProps) { +function TableLayout(props: TableLayoutProps) { const hasRows = props.tableInstance.getRowModel().rows.length > 0; return (
diff --git a/frontend/src/components/Table/features.ts b/frontend/src/components/Table/features.ts new file mode 100644 index 0000000000..9b79e1d596 --- /dev/null +++ b/frontend/src/components/Table/features.ts @@ -0,0 +1,35 @@ +import { + columnVisibilityFeature, + createSortedRowModel, + metaHelper, + rowSortingFeature, + tableFeatures, +} from "@tanstack/react-table"; + +interface ColumnMeta { + className?: string; +} + +interface TableMeta { + isFetching?: boolean; +} + +/** + * Shared TanStack Table v9 feature registration for every table in the app. + * Sorting and column visibility are used (or their APIs are called + * unconditionally, e.g. `getVisibleFlatColumns`/`getVisibleCells`) by the + * shared TableLayout/TableHeader/TableBody/EmptyData components, so every + * table instance must register them even when a particular table doesn't + * wire up controlled sorting state itself. + */ +const features = tableFeatures({ + rowSortingFeature, + sortedRowModel: createSortedRowModel(), + columnVisibilityFeature, + columnMeta: metaHelper(), + tableMeta: metaHelper(), +}); + +type Features = typeof features; + +export { type ColumnMeta, type Features, features, type TableMeta }; diff --git a/frontend/src/components/Table/index.ts b/frontend/src/components/Table/index.ts index d471d45d5c..84b64610a5 100644 --- a/frontend/src/components/Table/index.ts +++ b/frontend/src/components/Table/index.ts @@ -1,4 +1,5 @@ export * from "./Formatter"; +export * from "./features"; export * from "./TableHeader"; export * from "./TableHelpers"; export * from "./TableLayout"; diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 744190ade1..761c9578cf 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -10,7 +10,10 @@ export * from "./useDeadHosts"; export * from "./useDnsProviders"; export * from "./useHealth"; export * from "./useHostReport"; +export * from "./useLogSources"; +export * from "./useLogTail"; export * from "./useProxyHost"; +export * from "./useProxyHostLogs"; export * from "./useProxyHosts"; export * from "./useRedirectionHost"; export * from "./useRedirectionHosts"; diff --git a/frontend/src/hooks/useLogSources.ts b/frontend/src/hooks/useLogSources.ts new file mode 100644 index 0000000000..3f77bbd1ef --- /dev/null +++ b/frontend/src/hooks/useLogSources.ts @@ -0,0 +1,15 @@ +import { useQuery } from "@tanstack/react-query"; +import { getLogSources, type LogSources } from "src/api/backend"; + +const fetchLogSources = () => getLogSources(); + +const useLogSources = (options = {}) => { + return useQuery({ + queryKey: ["log-sources"], + queryFn: fetchLogSources, + staleTime: 30 * 1000, + ...options, + }); +}; + +export { fetchLogSources, useLogSources }; diff --git a/frontend/src/hooks/useLogTail.ts b/frontend/src/hooks/useLogTail.ts new file mode 100644 index 0000000000..d817dd0c11 --- /dev/null +++ b/frontend/src/hooks/useLogTail.ts @@ -0,0 +1,25 @@ +import { useQuery } from "@tanstack/react-query"; +import { type GetLogTailParams, getLogTail, type LogTail } from "src/api/backend"; + +const POLL_INTERVAL_MS = 5000; + +interface UseLogTailOptions extends GetLogTailParams { + live?: boolean; +} + +// Polls for new log lines while `live` is true. React Query only runs the interval +// while the tab is focused (refetchIntervalInBackground defaults to false), so an +// idle/backgrounded browser tab never generates load. +const useLogTail = ({ live = true, ...params }: UseLogTailOptions) => { + const enabled = params.type === "host" ? Boolean(params.hostType && params.hostId && params.channel) : true; + + return useQuery({ + queryKey: ["log-tail", params], + queryFn: () => getLogTail(params), + enabled, + refetchInterval: live ? POLL_INTERVAL_MS : false, + placeholderData: (previousData) => previousData, + }); +}; + +export { useLogTail }; diff --git a/frontend/src/hooks/useProxyHostLogs.ts b/frontend/src/hooks/useProxyHostLogs.ts new file mode 100644 index 0000000000..efcda1b682 --- /dev/null +++ b/frontend/src/hooks/useProxyHostLogs.ts @@ -0,0 +1,12 @@ +import { useQuery } from "@tanstack/react-query"; +import { getProxyHostLogs } from "src/api/backend"; + +const useProxyHostLogs = (id: number, type: "access" | "error" = "access") => { + return useQuery<{ logs: string }, Error>({ + queryKey: ["proxy-host-logs", id, type], + queryFn: () => getProxyHostLogs(id, type), + staleTime: 10_000, + }); +}; + +export { useProxyHostLogs }; diff --git a/frontend/src/locale/IntlProvider.tsx b/frontend/src/locale/IntlProvider.tsx old mode 100755 new mode 100644 index a5fb956c0d..671ef8ed5d --- a/frontend/src/locale/IntlProvider.tsx +++ b/frontend/src/locale/IntlProvider.tsx @@ -21,124 +21,143 @@ import langZh from "./lang/zh.json"; import langTr from "./lang/tr.json"; import langHu from "./lang/hu.json"; import langNo from "./lang/no.json"; +import langUk from "./lang/uk.json"; +import langAz from "./lang/az.json"; +import langFa from "./lang/fa.json"; import langList from "./lang/lang-list.json"; // first item of each array should be the language code, // not the country code // Remember when adding to this list, also update check-locales.js script const localeOptions = [ - ["en", "en-US", langEn], - ["de", "de-DE", langDe], - ["es", "es-ES", langEs], - ["et", "et-EE", langEt], - ["pt", "pt-PT", langPt], - ["fr", "fr-FR", langFr], - ["ga", "ga-IE", langGa], - ["ja", "ja-JP", langJa], - ["it", "it-IT", langIt], - ["nl", "nl-NL", langNl], - ["pl", "pl-PL", langPl], - ["ru", "ru-RU", langRu], - ["sk", "sk-SK", langSk], - ["cs", "cs-CZ", langCs], - ["vi", "vi-VN", langVi], - ["zh", "zh-CN", langZh], - ["ko", "ko-KR", langKo], - ["bg", "bg-BG", langBg], - ["id", "id-ID", langId], - ["tr", "tr-TR", langTr], - ["hu", "hu-HU", langHu], - ["no", "no-NO", langNo], + ["en", "en-US", langEn], + ["de", "de-DE", langDe], + ["es", "es-ES", langEs], + ["et", "et-EE", langEt], + ["pt", "pt-PT", langPt], + ["fr", "fr-FR", langFr], + ["ga", "ga-IE", langGa], + ["ja", "ja-JP", langJa], + ["it", "it-IT", langIt], + ["nl", "nl-NL", langNl], + ["pl", "pl-PL", langPl], + ["ru", "ru-RU", langRu], + ["sk", "sk-SK", langSk], + ["cs", "cs-CZ", langCs], + ["vi", "vi-VN", langVi], + ["zh", "zh-CN", langZh], + ["ko", "ko-KR", langKo], + ["bg", "bg-BG", langBg], + ["id", "id-ID", langId], + ["tr", "tr-TR", langTr], + ["hu", "hu-HU", langHu], + ["no", "no-NO", langNo], + ["uk", "uk-UA", langUk], + ["az", "az-AZ", langAz], + ["fa", "fa-IR", langFa], ]; const loadMessages = (locale?: string): typeof langList & typeof langEn => { - const thisLocale = (locale || "en").slice(0, 2); + const thisLocale = (locale || "en").slice(0, 2); - // ensure this lang exists in localeOptions above, otherwise fallback to en - if (thisLocale === "en" || !localeOptions.some(([code]) => code === thisLocale)) { - return Object.assign({}, langList, langEn); - } + // ensure this lang exists in localeOptions above, otherwise fallback to en + if (thisLocale === "en" || !localeOptions.some(([code]) => code === thisLocale)) { + return Object.assign({}, langList, langEn); + } - return Object.assign({}, langList, langEn, localeOptions.find(([code]) => code === thisLocale)?.[2]); + return Object.assign({}, langList, langEn, localeOptions.find(([code]) => code === thisLocale)?.[2]); }; const getFlagCodeForLocale = (locale?: string) => { - const thisLocale = (locale || "en").slice(0, 2); - - // only add to this if your flag is different from the locale code - const specialCases: Record = { - ja: "jp", // Japan - zh: "cn", // China - vi: "vn", // Vietnam - ko: "kr", // Korea - cs: "cz", // Czechia - ga: "ie", // Ireland (Irish) - }; - - if (specialCases[thisLocale]) { - return specialCases[thisLocale].toUpperCase(); - } - return thisLocale.toUpperCase(); + const thisLocale = (locale || "en").slice(0, 2); + + // only add to this if your flag is different from the locale code + const specialCases: Record = { + ja: "jp", // Japan + zh: "cn", // China + vi: "vn", // Vietnam + ko: "kr", // Korea + cs: "cz", // Czechia + ga: "ie", // Ireland (Irish) + et: "ee", // Estonia (ISO 3166-1). "et" as a country code would be Ethiopia. + uk: "ua", // Ukraine + fa: "ir", // Iran (Persian) + }; + + if (specialCases[thisLocale]) { + return specialCases[thisLocale].toUpperCase(); + } + return thisLocale.toUpperCase(); +}; + +const rtlLocales = ["fa"]; + +const isRTLLocale = (locale?: string) => rtlLocales.includes((locale || "en").slice(0, 2)); + +const applyDocumentLocale = (locale: string): void => { + document.documentElement.lang = locale; + document.documentElement.dir = isRTLLocale(locale) ? "rtl" : "ltr"; }; const getLocale = (short = false) => { - let loc = window.localStorage.getItem("locale"); - if (!loc) { - loc = document.documentElement.lang; - } - if (short) { - return loc.slice(0, 2); - } - // finally, fallback - if (!loc) { - loc = "en"; - } - return loc; + let loc = window.localStorage.getItem("locale"); + if (!loc) { + loc = document.documentElement.lang; + } + if (short) { + return loc.slice(0, 2); + } + // finally, fallback + if (!loc) { + loc = "en"; + } + return loc; }; const cache = createIntlCache(); const initialMessages = loadMessages(getLocale()); +applyDocumentLocale(getLocale()); let intl = createIntl({ locale: getLocale(), messages: initialMessages }, cache); const changeLocale = (locale: string): void => { - const messages = loadMessages(locale); - intl = createIntl({ locale, messages }, cache); - window.localStorage.setItem("locale", locale); - document.documentElement.lang = locale; + const messages = loadMessages(locale); + intl = createIntl({ locale, messages }, cache); + window.localStorage.setItem("locale", locale); + applyDocumentLocale(locale); }; // This is a translation component that wraps the translation in a span with a data // attribute so devs can inspect the element to see the translation ID const T = ({ - id, - data, - tData, + id, + data, + tData, }: { - id: string; - data?: Record; - tData?: Record; + id: string; + data?: Record; + tData?: Record; }) => { - const translatedData: Record = {}; - if (tData) { - // iterate over tData and translate each value - Object.entries(tData).forEach(([key, value]) => { - translatedData[key] = intl.formatMessage({ id: value }); - }); - } - return ( - - {intl.formatMessage( - { id }, - { - ...data, - ...translatedData, - }, - )} - - ); + const translatedData: Record = {}; + if (tData) { + // iterate over tData and translate each value + Object.entries(tData).forEach(([key, value]) => { + translatedData[key] = intl.formatMessage({ id: value }); + }); + } + return ( + + {intl.formatMessage( + { id }, + { + ...data, + ...translatedData, + }, + )} + + ); }; //console.log("L:", localeOptions); -export { localeOptions, getFlagCodeForLocale, getLocale, createIntl, changeLocale, intl, T }; +export { localeOptions, getFlagCodeForLocale, getLocale, isRTLLocale, createIntl, changeLocale, intl, T }; diff --git a/frontend/src/locale/Utils.test.tsx b/frontend/src/locale/Utils.test.tsx index a49460fee0..d1c4b26485 100644 --- a/frontend/src/locale/Utils.test.tsx +++ b/frontend/src/locale/Utils.test.tsx @@ -92,8 +92,23 @@ describe("getFlagCodeForLocale", () => { expect(getFlagCodeForLocale("ga-IE")).toBe("IE"); }); + it("returns EE (Estonia) for Estonian locale, not ET (Ethiopia)", () => { + expect(getFlagCodeForLocale("et")).toBe("EE"); + expect(getFlagCodeForLocale("et-EE")).toBe("EE"); + }); + it("falls back to EN when no locale is provided", () => { expect(getFlagCodeForLocale()).toBe("EN"); expect(getFlagCodeForLocale(undefined)).toBe("EN"); }); }); + +describe("formatDateTime Estonian locale", () => { + it("uses 24-hour clock for et and et-EE", () => { + const value = "2024-06-15T15:30:00.000Z"; + for (const locale of ["et", "et-EE"]) { + const text = formatDateTime(value, locale); + expect(text.toLowerCase()).not.toMatch(/\b(am|pm)\b/); + } + }); +}); diff --git a/frontend/src/locale/Utils.ts b/frontend/src/locale/Utils.ts index d422427737..9def46f806 100644 --- a/frontend/src/locale/Utils.ts +++ b/frontend/src/locale/Utils.ts @@ -1,9 +1,4 @@ -import { - fromUnixTime, - type IntlFormatFormatOptions, - intlFormat, - parseISO, -} from "date-fns"; +import { fromUnixTime, type IntlFormatFormatOptions, intlFormat, parseISO } from "date-fns"; const isUnixTimestamp = (value: unknown): boolean => { if (typeof value !== "number" && typeof value !== "string") return false; @@ -25,18 +20,29 @@ const parseDate = (value: string | number): Date | null => { } }; +const DATE_LOCALE_BY_LANG: Record = { + et: "et-EE", +}; + +const HOUR_CYCLE_BY_LANG: Record = { + et: "h23", +}; + const formatDateTime = (value: string | number, locale = "en-US"): string => { const d = parseDate(value); if (!d) return `${value}`; + const lang = (locale || "en").slice(0, 2); + const resolvedLocale = DATE_LOCALE_BY_LANG[lang] || locale; + const hourCycle = HOUR_CYCLE_BY_LANG[lang] || "h12"; try { return intlFormat( d, { dateStyle: "medium", timeStyle: "medium", - hourCycle: "h12", + hourCycle, } as IntlFormatFormatOptions, - { locale }, + { locale: resolvedLocale }, ); } catch { return `${value}`; diff --git a/frontend/src/locale/et.test.ts b/frontend/src/locale/et.test.ts new file mode 100644 index 0000000000..122dc3a521 --- /dev/null +++ b/frontend/src/locale/et.test.ts @@ -0,0 +1,67 @@ +import { describe, expect, it } from "vitest"; +import en from "./src/en.json"; +import et from "./src/et.json"; + +const english = en as Record; +const estonian = et as Record; + +// Brand names, codes and ICU-only strings can stay the same as English. +const allowedIdentical = new Set([ + "certificates.key-type-ecdsa", + "certificates.key-type-rsa", + "column.ssl", + "lets-encrypt", + "object.actions-title", + "streams.tcp", + "streams.udp", +]); + +describe("Estonian UI locale", () => { + it("covers every English UI key", () => { + const missing = Object.keys(english).filter((key) => !(key in estonian)); + expect(missing).toEqual([]); + }); + + it("does not add keys that are missing from English", () => { + const extra = Object.keys(estonian).filter((key) => !(key in english)); + expect(extra).toEqual([]); + }); + + it("is translated, not an English copy", () => { + const identical = Object.keys(english).filter( + (key) => estonian[key]?.defaultMessage === english[key]?.defaultMessage, + ); + const unexpected = identical.filter((key) => !allowedIdentical.has(key)); + expect(unexpected).toEqual([]); + }); + + it("keeps ICU data placeholders from English strings", () => { + const argNames = [ + "count", + "object", + "objects", + "id", + "date", + "users", + "rules", + "max", + "min", + "domain", + "code", + "latestVersion", + "name", + ]; + const usedArgs = (message: string) => argNames.filter((name) => message.includes(`{${name}`)); + const broken: string[] = []; + + for (const key of Object.keys(english)) { + const expected = usedArgs(english[key].defaultMessage).join(","); + const actual = usedArgs(estonian[key]?.defaultMessage ?? "").join(","); + if (expected !== actual) { + broken.push(`${key}: expected {${expected}} got {${actual}}`); + } + } + + expect(broken).toEqual([]); + }); +}); diff --git a/frontend/src/locale/src/HelpDoc/az/AccessLists.md b/frontend/src/locale/src/HelpDoc/az/AccessLists.md new file mode 100644 index 0000000000..f555dd577f --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/AccessLists.md @@ -0,0 +1,7 @@ +## Giriş siyahısı nədir? + +Giriş siyahıları müəyyən müştəri IP ünvanları üçün qara və ya ağ siyahı təqdim edir və Əsas HTTP Doğrulaması vasitəsilə Proksi Hostlar üçün autentifikasiya təmin edir. + +Tək bir Giriş siyahısı üçün bir neçə müştəri qaydası, istifadəçi adı və parol konfiqurasiya edə, sonra onu bir və ya bir neçə _Proksi Host_-a tətbiq edə bilərsiniz. + +Bu, öz daxili doğrulama mexanizmi olmayan yönləndirilən veb xidmətlər üçün və ya naməlum müştərilərdən qorunmaq istədiyiniz hallarda ən faydalıdır. diff --git a/frontend/src/locale/src/HelpDoc/az/Certificates.md b/frontend/src/locale/src/HelpDoc/az/Certificates.md new file mode 100644 index 0000000000..9e115a2eb7 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/Certificates.md @@ -0,0 +1,28 @@ +## Sertifikatlar üzrə kömək + +### HTTP Sertifikatı + +HTTP ilə doğrulanmış sertifikat o deməkdir ki, Let's Encrypt serverləri domenlərinizə +HTTP (HTTPS deyil!) üzərindən çatmağa cəhd edəcək və uğurlu olarsa sertifikatınızı verəcək. + +Bu üsul üçün domen(lər)iniz üçün HTTP ilə əlçatan olan və bu Nginx quraşdırmasına yönləndirilmiş bir +_Proksi Host_ yaratmalısınız. Sertifikat verildikdən sonra, _Proksi Host_-u HTTPS bağlantıları +üçün də bu sertifikatı istifadə etmək üzrə dəyişə bilərsiniz. Bununla belə, sertifikatın yenilənə bilməsi +üçün _Proksi Host_ hələ də HTTP girişi üçün konfiqurasiya edilmiş qalmalıdır. + +Bu proses wildcard domenləri dəstəkləmir. + +### DNS Sertifikatı + +DNS ilə doğrulanmış sertifikat DNS Provayder plaginindən istifadə etməyinizi tələb edir. Bu DNS +Provayderi domeninizdə müvəqqəti qeydlər yaratmaq üçün istifadə olunacaq, sonra Let's +Encrypt sizin sahibi olduğunuzu təsdiqləmək üçün həmin qeydləri sorğulayacaq və uğurlu olarsa sertifikatınızı verəcək. + +Bu tip sertifikatı sorğulamazdan əvvəl _Proksi Host_ yaratmağınıza ehtiyac yoxdur. Həmçinin +_Proksi Host_-unuzun HTTP girişi üçün konfiqurasiya edilməsinə də ehtiyac yoxdur. + +Bu proses wildcard domenləri dəstəkləyir. + +### Fərdi sertifikat + +Öz Sertifikat Səlahiyyətinizin verdiyi öz SSL Sertifikatınızı yükləmək üçün bu seçimdən istifadə edin. diff --git a/frontend/src/locale/src/HelpDoc/az/DeadHosts.md b/frontend/src/locale/src/HelpDoc/az/DeadHosts.md new file mode 100644 index 0000000000..4227a6254d --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/DeadHosts.md @@ -0,0 +1,10 @@ +## 404 Host nədir? + +404 Host, sadəcə 404 səhifəsi göstərən bir host quraşdırmasıdır. + +Bu, domeniniz axtarış sistemlərində siyahıya alındıqda və daha səliqəli bir xəta səhifəsi +göstərmək istədiyiniz zaman, ya da xüsusi olaraq axtarış indeksatorlarına domen səhifələrinin +artıq mövcud olmadığını bildirmək istədiyiniz zaman faydalı ola bilər. + +Bu hostu saxlamağın başqa bir faydası isə ona gələn müraciətlərin jurnallarını izləmək +və istinad edən mənbələrə baxmaqdır. diff --git a/frontend/src/locale/src/HelpDoc/az/ProxyHosts.md b/frontend/src/locale/src/HelpDoc/az/ProxyHosts.md new file mode 100644 index 0000000000..3ae260a3e4 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/ProxyHosts.md @@ -0,0 +1,7 @@ +## Proksi Host nədir? + +Proksi Host, yönləndirmək istədiyiniz veb xidmət üçün daxil olan giriş nöqtəsidir. + +O, öz daxili SSL dəstəyi olmaya bilən xidmətiniz üçün istəyə bağlı SSL sonlanması təmin edir. + +Proksi Hostlar Nginx Proxy Manager-in ən çox istifadə olunan funksiyasıdır. diff --git a/frontend/src/locale/src/HelpDoc/az/RedirectionHosts.md b/frontend/src/locale/src/HelpDoc/az/RedirectionHosts.md new file mode 100644 index 0000000000..9741fbc7ee --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/RedirectionHosts.md @@ -0,0 +1,8 @@ +## Yönləndirmə Hostu nədir? + +Yönləndirmə Hostu daxil olan domendən gələn sorğuları yönləndirəcək və izləyicini +başqa bir domenə göndərəcək. + +Bu tip hostdan istifadə etməyin ən çox rast gəlinən səbəbi veb saytınızın domeni +dəyişəndə, lakin axtarış sistemi və ya istinad edən linklərin hələ də köhnə domenə +işarə etdiyi hallardır. diff --git a/frontend/src/locale/src/HelpDoc/az/Streams.md b/frontend/src/locale/src/HelpDoc/az/Streams.md new file mode 100644 index 0000000000..a19d3baf62 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/Streams.md @@ -0,0 +1,6 @@ +## Axın (Stream) nədir? + +Nginx üçün nisbətən yeni bir funksiya olan Axın, TCP/UDP trafikini şəbəkədəki başqa +bir kompüterə birbaşa yönləndirməyə xidmət edir. + +Oyun serverləri, FTP və ya SSH serverləri işlədirsinizsə, bu funksiya faydalı ola bilər. diff --git a/frontend/src/locale/src/HelpDoc/az/index.ts b/frontend/src/locale/src/HelpDoc/az/index.ts new file mode 100644 index 0000000000..a9bb46ba7c --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/az/index.ts @@ -0,0 +1,6 @@ +export * as AccessLists from "./AccessLists.md"; +export * as Certificates from "./Certificates.md"; +export * as DeadHosts from "./DeadHosts.md"; +export * as ProxyHosts from "./ProxyHosts.md"; +export * as RedirectionHosts from "./RedirectionHosts.md"; +export * as Streams from "./Streams.md"; diff --git a/frontend/src/locale/src/HelpDoc/et/AccessLists.md b/frontend/src/locale/src/HelpDoc/et/AccessLists.md index 320214c4da..593d9a0945 100644 --- a/frontend/src/locale/src/HelpDoc/et/AccessLists.md +++ b/frontend/src/locale/src/HelpDoc/et/AccessLists.md @@ -1,7 +1,7 @@ ## Mis on juurdepääsuloend? -Ligipääsuloendid pakuvad konkreetsete klientide IP-aadresside musta või valget nimekirja koos puhverserverite autentimisega põhilise HTTP-autentimise kaudu. +Juurdepääsuloendiga saad lubada või keelata klientide IP-aadresse ning panna puhverserverile ette HTTP basic-autentimise. -Saate ühe juurdepääsuloendi jaoks konfigureerida mitu kliendireeglit, kasutajanime ja parooli ning seejärel rakendada neid ühele või mitmele _puhverserverile_. +Ühte loendisse saab panna mitu reeglit, kasutajanime ja parooli. Sama loendi saad kinnitada ühele või mitmele puhverserverile. -See on kõige kasulikum edastatud veebiteenuste puhul, millel pole sisseehitatud autentimismehhanisme või kui soovite kaitsta tundmatute klientide eest. \ No newline at end of file +Sellest on kasu siis, kui edastataval teenusel endal sisselogimist pole või tahad võõrad kliendid eemal hoida. diff --git a/frontend/src/locale/src/HelpDoc/et/Certificates.md b/frontend/src/locale/src/HelpDoc/et/Certificates.md index 551b57c439..4d6873f3ca 100644 --- a/frontend/src/locale/src/HelpDoc/et/Certificates.md +++ b/frontend/src/locale/src/HelpDoc/et/Certificates.md @@ -2,25 +2,20 @@ ### HTTP-sertifikaat -HTTP-valideeritud sertifikaat tähendab, et Let's Encrypti serverid +HTTP-ga kinnitatud sertifikaadi puhul üritavad Let's Encrypti serverid su domeenidele ligi saada HTTP kaudu (mitte HTTPS!) ja õnnestumise korral väljastavad sertifikaadi. -proovivad teie domeenidega ühendust luua HTTP (mitte HTTPS!) kaudu ja kui see õnnestub, -väljastavad nad teile sertifikaadi. +Selleks peab olema loodud puhverserver, mis on HTTP kaudu kättesaadav ja osutab sellele Nginxile. Kui sertifikaat on käes, võid puhverserveri panna HTTPS-i ka kasutama. Uuendamiseks peab HTTP-ligipääs siiski alles jääma. -Selle meetodi jaoks peate oma domeeni(de) jaoks looma _Proxy Host_, millele pääseb ligi HTTP kaudu ja mis osutab sellele Nginxi installile. Pärast sertifikaadi väljastamist saate muuta _Proxy Host_'i, et seda sertifikaati ka HTTPS -ühenduste jaoks kasutada. Sertifikaadi uuendamiseks tuleb aga _Proxy Host_ ikkagi HTTP-juurdepääsu jaoks konfigureerida. - -See protsess _ei_ toeta metamärke kasutavaid domeene. +Metamärgid (wildcard) selle meetodiga ei tööta. ### DNS-sertifikaat -DNS-i poolt valideeritud sertifikaadi saamiseks peate kasutama DNS-pakkuja pistikprogrammi. Seda DNS-teenuse pakkujat kasutatakse teie domeenis ajutiste kirjete loomiseks ja seejärel pärib Let's -Encrypt nende kirjete kohta päringu, et veenduda, et olete omanik, ja kui see õnnestub, väljastavad nad teile sertifikaadi. +DNS-iga kinnitatud sertifikaat vajab DNS-teenuse pakkuja pluginat. Plugin loob domeenile ajutised kirjed, Let's Encrypt kontrollib need üle ja õnnestumise korral väljastab sertifikaadi. -Selle tüüpi sertifikaadi taotlemiseks ei ole vaja luua _Proxy Host_'i. Samuti ei pea teie _Proxy Host_ olema HTTP-juurdepääsu jaoks konfigureeritud. +Puhverserverit enne taotlust looma ei pea. HTTP-ligipääsu ka ei nõuta. -See protsess _toetab_ metamärke kasutavaid domeene. +See meetod toetab metamärke. ### Kohandatud sertifikaat -Kasutage seda valikut oma SSL-sertifikaadi üleslaadimiseks, mille on esitanud teie enda sertifitseerimisasutus. \ No newline at end of file +Siia saad üles laadida oma SSL-sertifikaadi, mille on väljastanud sinu sertifitseerija. diff --git a/frontend/src/locale/src/HelpDoc/et/DeadHosts.md b/frontend/src/locale/src/HelpDoc/et/DeadHosts.md index 7bec575c8d..9281de16a3 100644 --- a/frontend/src/locale/src/HelpDoc/et/DeadHosts.md +++ b/frontend/src/locale/src/HelpDoc/et/DeadHosts.md @@ -1,9 +1,7 @@ -## Mis on 404 host? +## Mis on 404-host? -404 host on lihtsalt hosti seadistus, mis kuvab 404 lehte. +404-host on lihtsalt host, mis näitab 404 lehte. -See võib olla kasulik, kui teie domeen on otsingumootorites loetletud ja soovite -esitada kenama vealehe või konkreetselt otsingu indekseerijatele öelda, et -domeenilehed enam ei eksisteeri. +Sellest on abi, kui domeen on otsingumootorites kirjas ja tahad näidata kenamat vealehte või anda indekseerijatele märku, et lehti enam pole. -Selle hosti teine eelis on selle külastatavuste logide jälgimine ja suunajate vaatamine. \ No newline at end of file +Lisaks näed logist, kes sinna sattus ja kust nad tulid. diff --git a/frontend/src/locale/src/HelpDoc/et/ProxyHosts.md b/frontend/src/locale/src/HelpDoc/et/ProxyHosts.md index 9d10f528bf..65869031dc 100644 --- a/frontend/src/locale/src/HelpDoc/et/ProxyHosts.md +++ b/frontend/src/locale/src/HelpDoc/et/ProxyHosts.md @@ -1,7 +1,7 @@ ## Mis on puhverserver? -Puhverserver on veebiteenuse sissetuleva andmevoo lõpp-punkt, mida soovite edastada. +Puhverserver on veebiteenuse sisend, mille suunad edasi oma tegelikule teenusele. -See pakub valikulist SSL-i lõpetamist teie teenusele, millel ei pruugi olla sisseehitatud SSL-tuge. +Soovi korral lõpetab see SSL-i sinu eest — isegi kui teenusel endal SSL-tuge pole. -Puhverserverid on Nginxi puhverserveri halduri kõige levinum kasutusala. \ No newline at end of file +Puhverserverid on Nginx Proxy Manageri kõige tavalisem kasutus. diff --git a/frontend/src/locale/src/HelpDoc/et/RedirectionHosts.md b/frontend/src/locale/src/HelpDoc/et/RedirectionHosts.md index 8d3eaa06eb..cd5ecc8d24 100644 --- a/frontend/src/locale/src/HelpDoc/et/RedirectionHosts.md +++ b/frontend/src/locale/src/HelpDoc/et/RedirectionHosts.md @@ -1,5 +1,5 @@ ## Mis on ümbersuunamishost? -Ümbersuunamishost suunab sissetuleva domeeni päringud ümber ja suunab vaataja teisele domeenile. +Ümbersuunamishost võtab päringud ühelt domeenilt ja saadab külastaja teisele. -Kõige levinum põhjus seda tüüpi hosti kasutamiseks on see, kui teie veebisaidi domeenid muutuvad, kuid otsingumootori või suunaja lingid osutavad endiselt vanale domeenile. \ No newline at end of file +Kõige sagedamini on seda vaja siis, kui sait kolis uuele domeenile, aga vanad lingid otsingust või viidetest käivad veel vana aadressi pihta. diff --git a/frontend/src/locale/src/HelpDoc/et/Streams.md b/frontend/src/locale/src/HelpDoc/et/Streams.md index 55422c1823..bd1275a4ed 100644 --- a/frontend/src/locale/src/HelpDoc/et/Streams.md +++ b/frontend/src/locale/src/HelpDoc/et/Streams.md @@ -1,5 +1,5 @@ ## Mis on voog? -Nginxi suhteliselt uus funktsioon, voog, edastab TCP/UDP liiklust otse võrgus olevale teisele arvutile. +Voog on Nginxi suhteliselt uus võimalus suunata TCP/UDP liiklus otse teisele masinale võrgus. -Kui sul on mänguserverid, FTP- või SSH-serverid, võib see kasuks tulla. \ No newline at end of file +Kasulik näiteks mängu-, FTP- või SSH-serverite puhul. diff --git a/frontend/src/locale/src/HelpDoc/et/index.ts b/frontend/src/locale/src/HelpDoc/et/index.ts index d0178a5d30..a9bb46ba7c 100644 --- a/frontend/src/locale/src/HelpDoc/et/index.ts +++ b/frontend/src/locale/src/HelpDoc/et/index.ts @@ -3,4 +3,4 @@ export * as Certificates from "./Certificates.md"; export * as DeadHosts from "./DeadHosts.md"; export * as ProxyHosts from "./ProxyHosts.md"; export * as RedirectionHosts from "./RedirectionHosts.md"; -export * as Streams from "./Streams.md"; \ No newline at end of file +export * as Streams from "./Streams.md"; diff --git a/frontend/src/locale/src/HelpDoc/fa/AccessLists.md b/frontend/src/locale/src/HelpDoc/fa/AccessLists.md new file mode 100644 index 0000000000..d9d5fe53d5 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/AccessLists.md @@ -0,0 +1,7 @@ +## فهرست دسترسی چیست؟ + +فهرست دسترسی (Access List) به شما اجازه می‌دهد دسترسی آدرس‌های IP مشخص را مجاز یا مسدود کنید و در صورت نیاز با استفاده از Basic HTTP Authentication از Proxy Hostها با نام کاربری و رمز عبور محافظت کنید. + +در هر فهرست دسترسی می‌توانید چندین قانون برای کلاینت‌ها و چندین نام کاربری و رمز عبور تعریف کنید و سپس همان فهرست را به یک یا چند _میزبان پراکسی (Proxy Host)_ اختصاص دهید. + +این قابلیت برای سرویس‌های وبی که خودشان مکانیزم احراز هویت ندارند، یا زمانی که می‌خواهید دسترسی کلاینت‌های ناشناس را محدود کنید، بسیار کاربردی است. diff --git a/frontend/src/locale/src/HelpDoc/fa/Certificates.md b/frontend/src/locale/src/HelpDoc/fa/Certificates.md new file mode 100644 index 0000000000..f65f96956d --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/Certificates.md @@ -0,0 +1,21 @@ +## راهنمای گواهی‌ها + +### گواهی HTTP + +در اعتبارسنجی از طریق HTTP، سرورهای Let's Encrypt تلاش می‌کنند از طریق HTTP (نه HTTPS) به دامنهٔ شما دسترسی پیدا کنند. اگر اعتبارسنجی موفق باشد، گواهی صادر می‌شود. + +برای این روش باید از قبل یک _میزبان پراکسی (Proxy Host)_ برای دامنهٔ موردنظر ایجاد کرده باشید که از طریق HTTP در دسترس باشد و به همین نصب Nginx Proxy Manager اشاره کند. پس از صدور گواهی می‌توانید Proxy Host را طوری تنظیم کنید که برای اتصال‌های HTTPS نیز از آن استفاده کند. با این حال، برای تمدید خودکار گواهی، دسترسی HTTP باید همچنان برقرار بماند. + +این روش از دامنه‌های Wildcard پشتیبانی _نمی‌کند_. + +### گواهی DNS + +در اعتبارسنجی از طریق DNS باید از افزونهٔ ارائه‌دهندهٔ DNS (DNS Provider) استفاده کنید. افزونه به‌طور موقت رکوردهایی در DNS دامنه ایجاد می‌کند و Let's Encrypt با بررسی آن‌ها مالکیت دامنه را تأیید می‌کند. در صورت موفقیت، گواهی صادر می‌شود. + +برای درخواست این نوع گواهی لازم نیست از قبل Proxy Host ساخته باشید و Proxy Host نیز نیازی به دسترسی HTTP ندارد. + +این روش از دامنه‌های Wildcard پشتیبانی _می‌کند_. + +### گواهی سفارشی + +از این گزینه برای بارگذاری گواهی SSL/TLS خود که توسط مرجع صدور گواهی (CA) موردنظر شما صادر شده است استفاده کنید. diff --git a/frontend/src/locale/src/HelpDoc/fa/DeadHosts.md b/frontend/src/locale/src/HelpDoc/fa/DeadHosts.md new file mode 100644 index 0000000000..42db654c1d --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/DeadHosts.md @@ -0,0 +1,7 @@ +## میزبان 404 چیست؟ + +میزبان 404 (404 Host) میزبانی است که برای درخواست‌های ورودی یک صفحهٔ 404 نمایش می‌دهد. + +این قابلیت زمانی مفید است که دامنهٔ شما هنوز در موتورهای جست‌وجو فهرست شده است و می‌خواهید صفحهٔ خطای مناسب‌تری نمایش دهید، یا به خزنده‌های موتورهای جست‌وجو اعلام کنید که صفحات آن دامنه دیگر وجود ندارند. + +همچنین می‌توانید لاگ درخواست‌های ورودی به این Host و آدرس‌های ارجاع‌دهنده (Referrer) را بررسی کنید. diff --git a/frontend/src/locale/src/HelpDoc/fa/ProxyHosts.md b/frontend/src/locale/src/HelpDoc/fa/ProxyHosts.md new file mode 100644 index 0000000000..2ef0fcf5b2 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/ProxyHosts.md @@ -0,0 +1,7 @@ +## میزبان پراکسی چیست؟ + +میزبان پراکسی (Proxy Host) نقطهٔ ورودی برای یک سرویس وب است که می‌خواهید درخواست‌ها را به آن فوروارد کنید. + +Proxy Host می‌تواند SSL/TLS Termination را نیز انجام دهد؛ بنابراین حتی اگر سرویس مقصد خودش SSL نداشته باشد، می‌توانید دسترسی HTTPS را در Nginx Proxy Manager فراهم کنید. + +Proxy Hostها رایج‌ترین قابلیت مورد استفاده در Nginx Proxy Manager هستند. diff --git a/frontend/src/locale/src/HelpDoc/fa/RedirectionHosts.md b/frontend/src/locale/src/HelpDoc/fa/RedirectionHosts.md new file mode 100644 index 0000000000..65f09f96a0 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/RedirectionHosts.md @@ -0,0 +1,5 @@ +## میزبان تغییر مسیر چیست؟ + +میزبان تغییر مسیر (Redirection Host) درخواست‌های دامنهٔ ورودی را به دامنهٔ دیگری Redirect می‌کند. + +کاربرد رایج آن زمانی است که دامنهٔ وب‌سایت تغییر کرده، اما نتایج موتورهای جست‌وجو یا لینک‌های ارجاع‌دهنده هنوز به دامنهٔ قدیمی اشاره می‌کنند. diff --git a/frontend/src/locale/src/HelpDoc/fa/Streams.md b/frontend/src/locale/src/HelpDoc/fa/Streams.md new file mode 100644 index 0000000000..9896e2c00a --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/Streams.md @@ -0,0 +1,5 @@ +## استریم چیست؟ + +Stream در Nginx برای فوروارد کردن مستقیم ترافیک TCP/UDP به یک میزبان دیگر در شبکه استفاده می‌شود. + +این قابلیت برای سرویس‌هایی مانند سرورهای بازی، FTP، SSH و سایر سرویس‌های مبتنی بر TCP یا UDP کاربرد دارد. diff --git a/frontend/src/locale/src/HelpDoc/fa/index.ts b/frontend/src/locale/src/HelpDoc/fa/index.ts new file mode 100644 index 0000000000..a9bb46ba7c --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/fa/index.ts @@ -0,0 +1,6 @@ +export * as AccessLists from "./AccessLists.md"; +export * as Certificates from "./Certificates.md"; +export * as DeadHosts from "./DeadHosts.md"; +export * as ProxyHosts from "./ProxyHosts.md"; +export * as RedirectionHosts from "./RedirectionHosts.md"; +export * as Streams from "./Streams.md"; diff --git a/frontend/src/locale/src/HelpDoc/index.ts b/frontend/src/locale/src/HelpDoc/index.ts index 7d4af5f5dd..ceddf4c785 100644 --- a/frontend/src/locale/src/HelpDoc/index.ts +++ b/frontend/src/locale/src/HelpDoc/index.ts @@ -19,21 +19,23 @@ import * as vi from "./vi/index"; import * as zh from "./zh/index"; import * as tr from "./tr/index"; import * as hu from "./hu/index"; +import * as uk from "./uk/index"; +import * as az from "./az/index"; +import * as fa from "./fa/index"; -const items: any = { en, de, pt, es, et, ja, sk, cs, zh, pl, ru, it, vi, nl, bg, ko, ga, id, fr, tr, hu }; - +const items: any = { en, de, pt, es, et, ja, sk, cs, zh, pl, ru, it, vi, nl, bg, ko, ga, id, fr, tr, hu, uk, az, fa }; const fallbackLang = "en"; export const getHelpFile = (lang: string, section: string): string => { - if (typeof items[lang] !== "undefined" && typeof items[lang][section] !== "undefined") { - return items[lang][section].default; - } - // Fallback to English - if (typeof items[fallbackLang] !== "undefined" && typeof items[fallbackLang][section] !== "undefined") { - return items[fallbackLang][section].default; - } - throw new Error(`Cannot load help doc for ${lang}-${section}`); + if (typeof items[lang] !== "undefined" && typeof items[lang][section] !== "undefined") { + return items[lang][section].default; + } + // Fallback to English + if (typeof items[fallbackLang] !== "undefined" && typeof items[fallbackLang][section] !== "undefined") { + return items[fallbackLang][section].default; + } + throw new Error(`Cannot load help doc for ${lang}-${section}`); }; export default items; diff --git a/frontend/src/locale/src/HelpDoc/ko/index.ts b/frontend/src/locale/src/HelpDoc/ko/index.ts index 33e015cc81..a9bb46ba7c 100644 --- a/frontend/src/locale/src/HelpDoc/ko/index.ts +++ b/frontend/src/locale/src/HelpDoc/ko/index.ts @@ -4,4 +4,3 @@ export * as DeadHosts from "./DeadHosts.md"; export * as ProxyHosts from "./ProxyHosts.md"; export * as RedirectionHosts from "./RedirectionHosts.md"; export * as Streams from "./Streams.md"; - diff --git a/frontend/src/locale/src/HelpDoc/tr/index.ts b/frontend/src/locale/src/HelpDoc/tr/index.ts index 33e015cc81..a9bb46ba7c 100644 --- a/frontend/src/locale/src/HelpDoc/tr/index.ts +++ b/frontend/src/locale/src/HelpDoc/tr/index.ts @@ -4,4 +4,3 @@ export * as DeadHosts from "./DeadHosts.md"; export * as ProxyHosts from "./ProxyHosts.md"; export * as RedirectionHosts from "./RedirectionHosts.md"; export * as Streams from "./Streams.md"; - diff --git a/frontend/src/locale/src/HelpDoc/uk/AccessLists.md b/frontend/src/locale/src/HelpDoc/uk/AccessLists.md new file mode 100644 index 0000000000..3cadbf2443 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/AccessLists.md @@ -0,0 +1,7 @@ +## Що таке список доступу? + +Списки доступу дають змогу створити список дозволених або заборонених IP-адрес клієнтів, а також налаштувати автентифікацію для проксі-хостів за допомогою базової HTTP-автентифікації. + +Для одного списку доступу можна налаштувати кілька правил для клієнтів, імен користувачів і паролів, а потім застосувати його до одного або кількох _проксі-хостів_. + +Це особливо корисно для проксійованих вебсервісів, які не мають власних механізмів автентифікації, або коли потрібно захистити їх від невідомих клієнтів. diff --git a/frontend/src/locale/src/HelpDoc/uk/Certificates.md b/frontend/src/locale/src/HelpDoc/uk/Certificates.md new file mode 100644 index 0000000000..c1f7459d6d --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/Certificates.md @@ -0,0 +1,21 @@ +## Довідка щодо сертифікатів + +### HTTP-сертифікат + +Під час перевірки сертифіката через HTTP сервери Let's Encrypt спробують отримати доступ до ваших доменів через HTTP (не HTTPS!). Якщо перевірка буде успішною, вони видадуть сертифікат. + +Для цього методу потрібно створити _проксі-хост_ для відповідних доменів. Він має бути доступним через HTTP і вказувати на цей екземпляр Nginx. Після отримання сертифіката можна налаштувати _проксі-хост_ на використання цього сертифіката для HTTPS-з'єднань. Однак для автоматичного поновлення сертифіката _проксі-хост_ і надалі має бути доступним через HTTP. + +Цей спосіб _не підтримує_ підстановчі домени. + +### DNS-сертифікат + +Для перевірки сертифіката через DNS потрібно використати плагін DNS-провайдера. За допомогою цього плагіна буде створено тимчасові записи у вашому домені. Let's Encrypt перевірить ці записи, щоб підтвердити, що домен належить вам, і в разі успішної перевірки видасть сертифікат. + +Перед запитом такого сертифіката не потрібно створювати _проксі-хост_ або налаштовувати для нього доступ через HTTP. + +Цей спосіб _підтримує_ підстановчі домени. + +### Власний сертифікат + +Скористайтеся цим варіантом, щоб завантажити власний SSL-сертифікат, виданий вашим центром сертифікації. diff --git a/frontend/src/locale/src/HelpDoc/uk/DeadHosts.md b/frontend/src/locale/src/HelpDoc/uk/DeadHosts.md new file mode 100644 index 0000000000..a606bdc249 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/DeadHosts.md @@ -0,0 +1,7 @@ +## Що таке 404-хост? + +404-хост — це хост, налаштований для показу сторінки з помилкою 404. + +Він може бути корисним, якщо ваш домен проіндексовано пошуковими системами й ви хочете показати зрозумілішу сторінку помилки або повідомити пошуковим роботам, що сторінки домену більше не існують. + +Також цей хост дає змогу відстежувати звернення до нього в журналах і переглядати джерела переходів. diff --git a/frontend/src/locale/src/HelpDoc/uk/ProxyHosts.md b/frontend/src/locale/src/HelpDoc/uk/ProxyHosts.md new file mode 100644 index 0000000000..a5df6d6e42 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/ProxyHosts.md @@ -0,0 +1,7 @@ +## Що таке проксі-хост? + +Проксі-хост — це вхідна точка для вебсервісу, до якого потрібно перенаправляти запити. + +Він дає змогу за потреби завершувати SSL-з'єднання для сервісу, який може не мати вбудованої підтримки SSL. + +Проксі-хости — найпоширеніший спосіб використання Nginx Proxy Manager. diff --git a/frontend/src/locale/src/HelpDoc/uk/RedirectionHosts.md b/frontend/src/locale/src/HelpDoc/uk/RedirectionHosts.md new file mode 100644 index 0000000000..79b70f7b99 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/RedirectionHosts.md @@ -0,0 +1,5 @@ +## Що таке редирект-хост? + +Редирект-хост перенаправляє запити з вхідного домену на інший домен. + +Найчастіше такий хост використовують після зміни домену вебсайту, коли в пошукових системах або на інших сайтах ще залишилися посилання на старий домен. diff --git a/frontend/src/locale/src/HelpDoc/uk/Streams.md b/frontend/src/locale/src/HelpDoc/uk/Streams.md new file mode 100644 index 0000000000..f50cb9e517 --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/Streams.md @@ -0,0 +1,5 @@ +## Що таке потік? + +Потік — це відносно нова функція Nginx, яка дає змогу перенаправляти TCP/UDP-трафік безпосередньо на інший комп'ютер у мережі. + +Це може бути корисним, якщо ви використовуєте ігрові, FTP- або SSH-сервери. diff --git a/frontend/src/locale/src/HelpDoc/uk/index.ts b/frontend/src/locale/src/HelpDoc/uk/index.ts new file mode 100644 index 0000000000..a9bb46ba7c --- /dev/null +++ b/frontend/src/locale/src/HelpDoc/uk/index.ts @@ -0,0 +1,6 @@ +export * as AccessLists from "./AccessLists.md"; +export * as Certificates from "./Certificates.md"; +export * as DeadHosts from "./DeadHosts.md"; +export * as ProxyHosts from "./ProxyHosts.md"; +export * as RedirectionHosts from "./RedirectionHosts.md"; +export * as Streams from "./Streams.md"; diff --git a/frontend/src/locale/src/az.json b/frontend/src/locale/src/az.json new file mode 100644 index 0000000000..f76786491b --- /dev/null +++ b/frontend/src/locale/src/az.json @@ -0,0 +1,785 @@ +{ + "2fa.backup-codes-remaining": { + "defaultMessage": "Qalan ehtiyat kodları: {count}" + }, + "2fa.backup-warning": { + "defaultMessage": "Bu ehtiyat kodlarını təhlükəsiz yerdə saxlayın. Hər kod yalnız bir dəfə istifadə oluna bilər." + }, + "2fa.disable": { + "defaultMessage": "İkifaktorlu doğrulamanı söndür" + }, + "2fa.disable-confirm": { + "defaultMessage": "2FA-nı söndür" + }, + "2fa.disable-warning": { + "defaultMessage": "İkifaktorlu doğrulamanı söndürmək hesabınızın təhlükəsizliyini azaldacaq." + }, + "2fa.disabled": { + "defaultMessage": "Deaktiv" + }, + "2fa.done": { + "defaultMessage": "Ehtiyat kodlarımı yadda saxladım" + }, + "2fa.enable": { + "defaultMessage": "İkifaktorlu doğrulamanı aktivləşdir" + }, + "2fa.enabled": { + "defaultMessage": "Aktivdir" + }, + "2fa.enter-code": { + "defaultMessage": "Doğrulama kodunu daxil edin" + }, + "2fa.enter-code-disable": { + "defaultMessage": "Söndürmək üçün doğrulama kodunu daxil edin" + }, + "2fa.regenerate": { + "defaultMessage": "Yenidən yarat" + }, + "2fa.regenerate-backup": { + "defaultMessage": "Ehtiyat kodlarını yenidən yarat" + }, + "2fa.regenerate-instructions": { + "defaultMessage": "Yeni ehtiyat kodları yaratmaq üçün doğrulama kodunu daxil edin. Köhnə kodlarınız etibarsız olacaq." + }, + "2fa.secret-key": { + "defaultMessage": "Gizli açar" + }, + "2fa.setup-instructions": { + "defaultMessage": "Bu QR kodu doğrulama tətbiqinizlə skan edin və ya gizli açarı əl ilə daxil edin." + }, + "2fa.status": { + "defaultMessage": "Vəziyyət" + }, + "2fa.title": { + "defaultMessage": "İkifaktorlu doğrulama" + }, + "2fa.verify-enable": { + "defaultMessage": "Doğrula və aktivləşdir" + }, + "access-list": { + "defaultMessage": "Giriş siyahısı" + }, + "access-list.access-count": { + "defaultMessage": "{count} {count, plural, one {qayda} other {qayda}}" + }, + "access-list.auth-count": { + "defaultMessage": "{count} {count, plural, one {istifadəçi} other {istifadəçi}}" + }, + "access-list.help-rules-last": { + "defaultMessage": "Ən azı 1 qayda mövcud olduqda, bu qadağan et qaydası ən sona əlavə olunacaq" + }, + "access-list.help.rules-order": { + "defaultMessage": "Nəzərə alın ki, icazə ver və qadağan et direktivləri təyin edildikləri sırada tətbiq olunacaq." + }, + "access-list.pass-auth": { + "defaultMessage": "Doğrulamanı yuxarı axına ötür" + }, + "access-list.public": { + "defaultMessage": "İctimai əlçatan" + }, + "access-list.public.subtitle": { + "defaultMessage": "Əsas doğrulama tələb olunmur" + }, + "access-list.rule-source.placeholder": { + "defaultMessage": "192.168.1.100 və ya 192.168.1.0/24 və ya 2001:0db8::/32" + }, + "access-list.satisfy-any": { + "defaultMessage": "İstənilən şərti ödə" + }, + "access-list.subtitle": { + "defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Rule} other {Rules}} - Yaradılıb: {date}" + }, + "access-lists": { + "defaultMessage": "Giriş siyahıları" + }, + "action.add": { + "defaultMessage": "Əlavə et" + }, + "action.add-location": { + "defaultMessage": "Məkan əlavə et" + }, + "action.allow": { + "defaultMessage": "İcazə ver" + }, + "action.clear": { + "defaultMessage": "Təmizlə" + }, + "action.close": { + "defaultMessage": "Bağla" + }, + "action.delete": { + "defaultMessage": "Sil" + }, + "action.deny": { + "defaultMessage": "Qadağan et" + }, + "action.disable": { + "defaultMessage": "Söndür" + }, + "action.download": { + "defaultMessage": "Endir" + }, + "action.edit": { + "defaultMessage": "Redaktə et" + }, + "action.enable": { + "defaultMessage": "Aktivləşdir" + }, + "action.permissions": { + "defaultMessage": "İcazələr" + }, + "action.renew": { + "defaultMessage": "Yenilə" + }, + "action.view-details": { + "defaultMessage": "Ətraflı bax" + }, + "auditlogs": { + "defaultMessage": "Audit jurnalları" + }, + "auto": { + "defaultMessage": "Avtomatik" + }, + "cancel": { + "defaultMessage": "Ləğv et" + }, + "certificate": { + "defaultMessage": "Sertifikat" + }, + "certificate.custom-certificate": { + "defaultMessage": "Sertifikat" + }, + "certificate.custom-certificate-key": { + "defaultMessage": "Sertifikat açarı" + }, + "certificate.custom-intermediate": { + "defaultMessage": "Aralıq sertifikat" + }, + "certificate.in-use": { + "defaultMessage": "İstifadədədir" + }, + "certificate.none.subtitle": { + "defaultMessage": "Sertifikat təyin edilməyib" + }, + "certificate.none.subtitle.for-http": { + "defaultMessage": "Bu host HTTPS istifadə etməyəcək" + }, + "certificate.none.title": { + "defaultMessage": "Yoxdur" + }, + "certificate.not-in-use": { + "defaultMessage": "İstifadə olunmur" + }, + "certificate.renew": { + "defaultMessage": "Sertifikatı yenilə" + }, + "certificates": { + "defaultMessage": "Sertifikatlar" + }, + "certificates.custom": { + "defaultMessage": "Fərdi sertifikat" + }, + "certificates.custom.warning": { + "defaultMessage": "Şifrə ilə qorunan açar faylları dəstəklənmir." + }, + "certificates.dns.credentials": { + "defaultMessage": "Giriş məlumatları faylının məzmunu" + }, + "certificates.dns.credentials-note": { + "defaultMessage": "Bu plagin provayderiniz üçün API tokeni və ya digər giriş məlumatlarını ehtiva edən konfiqurasiya faylı tələb edir" + }, + "certificates.dns.credentials-warning": { + "defaultMessage": "Bu məlumat verilənlər bazasında və bir faylda açıq mətn kimi saxlanılacaq!" + }, + "certificates.dns.propagation-seconds": { + "defaultMessage": "Yayılma saniyələri" + }, + "certificates.dns.propagation-seconds-note": { + "defaultMessage": "Plaginin standart dəyərini istifadə etmək üçün boş buraxın. DNS yayılmasını gözləmək üçün saniyələrin sayı." + }, + "certificates.dns.provider": { + "defaultMessage": "DNS provayderi" + }, + "certificates.dns.provider.placeholder": { + "defaultMessage": "Provayder seçin..." + }, + "certificates.dns.warning": { + "defaultMessage": "Bu bölmə Certbot və onun DNS plaginləri haqqında müəyyən bilik tələb edir. Zəhmət olmasa müvafiq plaginlərin sənədləri ilə tanış olun." + }, + "certificates.http.reachability-404": { + "defaultMessage": "Bu domendə server tapıldı, lakin bu Nginx Proxy Manager kimi görünmür. Zəhmət olmasa domeninizin NPM instansiyanızın işlədiyi IP-yə yönləndirildiyinə əmin olun." + }, + "certificates.http.reachability-failed-to-check": { + "defaultMessage": "site24x7.com ilə əlaqə xətası səbəbindən əlçatanlığı yoxlamaq mümkün olmadı." + }, + "certificates.http.reachability-not-resolved": { + "defaultMessage": "Bu domendə heç bir server mövcud deyil. Zəhmət olmasa domeninizin mövcud olduğuna, NPM instansiyanızın işlədiyi IP-yə yönləndirildiyinə və lazım gələrsə routerinizdə 80 portunun yönləndirildiyinə əmin olun." + }, + "certificates.http.reachability-ok": { + "defaultMessage": "Serveriniz əlçatandır və sertifikat yaratmaq mümkün olmalıdır." + }, + "certificates.http.reachability-other": { + "defaultMessage": "Bu domendə server tapıldı, lakin gözlənilməz status kodu qaytardı: {code}. Bu NPM serveridirmi? Zəhmət olmasa domeninizin NPM instansiyanızın işlədiyi IP-yə yönləndirildiyinə əmin olun." + }, + "certificates.http.reachability-wrong-data": { + "defaultMessage": "Bu domendə server tapıldı, lakin gözlənilməz məlumat qaytardı. Bu NPM serveridirmi? Zəhmət olmasa domeninizin NPM instansiyanızın işlədiyi IP-yə yönləndirildiyinə əmin olun." + }, + "certificates.http.test-results": { + "defaultMessage": "Test nəticələri" + }, + "certificates.http.warning": { + "defaultMessage": "Bu domenlər artıq bu quraşdırmaya yönləndirilmiş şəkildə konfiqurasiya edilmiş olmalıdır." + }, + "certificates.key-type": { + "defaultMessage": "Açar növü" + }, + "certificates.key-type-description": { + "defaultMessage": "RSA geniş uyğunluğa malikdir, ECDSA daha sürətli və təhlükəsizdir, lakin köhnə sistemlərdə dəstəklənməyə bilər" + }, + "certificates.key-type-ecdsa": { + "defaultMessage": "ECDSA 256" + }, + "certificates.key-type-rsa": { + "defaultMessage": "RSA 2048" + }, + "certificates.request.subtitle": { + "defaultMessage": "Let's Encrypt ilə" + }, + "certificates.request.title": { + "defaultMessage": "Yeni sertifikat sorğula" + }, + "column.access": { + "defaultMessage": "Giriş" + }, + "column.authorization": { + "defaultMessage": "Səlahiyyət" + }, + "column.authorizations": { + "defaultMessage": "Səlahiyyətlər" + }, + "column.custom-locations": { + "defaultMessage": "Fərdi məkanlar" + }, + "column.destination": { + "defaultMessage": "Təyinat" + }, + "column.details": { + "defaultMessage": "Təfərrüatlar" + }, + "column.email": { + "defaultMessage": "E-poçt" + }, + "column.event": { + "defaultMessage": "Hadisə" + }, + "column.expires": { + "defaultMessage": "Bitmə tarixi" + }, + "column.http-code": { + "defaultMessage": "HTTP kodu" + }, + "column.incoming-port": { + "defaultMessage": "Daxil olan port" + }, + "column.name": { + "defaultMessage": "Ad" + }, + "column.protocol": { + "defaultMessage": "Protokol" + }, + "column.provider": { + "defaultMessage": "Provayder" + }, + "column.roles": { + "defaultMessage": "Rollar" + }, + "column.rules": { + "defaultMessage": "Qaydalar" + }, + "column.satisfy": { + "defaultMessage": "Şərt" + }, + "column.satisfy-all": { + "defaultMessage": "Hamısı" + }, + "column.satisfy-any": { + "defaultMessage": "İstənilən" + }, + "column.scheme": { + "defaultMessage": "Sxem" + }, + "column.source": { + "defaultMessage": "Mənbə" + }, + "column.ssl": { + "defaultMessage": "SSL" + }, + "column.status": { + "defaultMessage": "Vəziyyət" + }, + "created-on": { + "defaultMessage": "Yaradılıb: {date}" + }, + "dashboard": { + "defaultMessage": "İdarə paneli" + }, + "dead-host": { + "defaultMessage": "404 Host" + }, + "dead-hosts": { + "defaultMessage": "404 Hostlar" + }, + "dead-hosts.count": { + "defaultMessage": "{count} {count, plural, one {404 host} other {404 host}}" + }, + "disabled": { + "defaultMessage": "Deaktiv" + }, + "domain-names": { + "defaultMessage": "Domen adları" + }, + "domain-names.max": { + "defaultMessage": "Maksimum {count} domen adı" + }, + "domain-names.placeholder": { + "defaultMessage": "Domen əlavə etmək üçün yazmağa başlayın..." + }, + "domain-names.wildcards-not-permitted": { + "defaultMessage": "Bu növ üçün wildcard-lara icazə verilmir" + }, + "domain-names.wildcards-not-supported": { + "defaultMessage": "Bu CA üçün wildcard-lar dəstəklənmir" + }, + "domains.advanced": { + "defaultMessage": "Əlavə" + }, + "domains.force-ssl": { + "defaultMessage": "SSL-i məcburi et" + }, + "domains.hsts-enabled": { + "defaultMessage": "HSTS aktivdir" + }, + "domains.hsts-subdomains": { + "defaultMessage": "HSTS alt-domenləri" + }, + "domains.http2-support": { + "defaultMessage": "HTTP/2 dəstəyi" + }, + "domains.trust-forwarded-proto": { + "defaultMessage": "Yuxarı axından yönləndirilən Proto başlıqlarına etibar et" + }, + "domains.use-dns": { + "defaultMessage": "DNS Challenge-dən istifadə et" + }, + "email-address": { + "defaultMessage": "E-poçt ünvanı" + }, + "empty-search": { + "defaultMessage": "Nəticə tapılmadı" + }, + "empty-subtitle": { + "defaultMessage": "Niyə bir dənə yaratmırsınız?" + }, + "enabled": { + "defaultMessage": "Aktivdir" + }, + "error.access.at-least-one": { + "defaultMessage": "Ya bir Səlahiyyət, ya da bir Giriş Qaydası tələb olunur" + }, + "error.access.duplicate-usernames": { + "defaultMessage": "Səlahiyyət istifadəçi adları unikal olmalıdır" + }, + "error.invalid-auth": { + "defaultMessage": "Yanlış e-poçt və ya parol" + }, + "error.invalid-domain": { + "defaultMessage": "Yanlış domen: {domain}" + }, + "error.invalid-email": { + "defaultMessage": "Yanlış e-poçt ünvanı" + }, + "error.max-character-length": { + "defaultMessage": "Maksimum uzunluq {max} simvol{max, plural, one {} other {s}}" + }, + "error.max-domains": { + "defaultMessage": "Çox sayda domen, maksimum {max}" + }, + "error.maximum": { + "defaultMessage": "Maksimum {max}" + }, + "error.min-character-length": { + "defaultMessage": "Minimum uzunluq {min} simvol{min, plural, one {} other {s}}" + }, + "error.minimum": { + "defaultMessage": "Minimum {min}" + }, + "error.passwords-must-match": { + "defaultMessage": "Parollar uyğun gəlməlidir" + }, + "error.required": { + "defaultMessage": "Bu tələb olunur" + }, + "expires.on": { + "defaultMessage": "Bitmə tarixi: {date}" + }, + "footer.github-fork": { + "defaultMessage": "Github-da fork et" + }, + "host.flags.block-exploits": { + "defaultMessage": "Ümumi hücumları blokla" + }, + "host.flags.cache-assets": { + "defaultMessage": "Statik faylları keşlə" + }, + "host.flags.preserve-path": { + "defaultMessage": "Yolu saxla" + }, + "host.flags.protocols": { + "defaultMessage": "Protokollar" + }, + "host.flags.websockets-upgrade": { + "defaultMessage": "Websocket dəstəyi" + }, + "host.forward-port": { + "defaultMessage": "Yönləndirmə portu" + }, + "host.forward-scheme": { + "defaultMessage": "Sxem" + }, + "hosts": { + "defaultMessage": "Hostlar" + }, + "http-only": { + "defaultMessage": "Yalnız HTTP" + }, + "lets-encrypt": { + "defaultMessage": "Let's Encrypt" + }, + "lets-encrypt-via-dns": { + "defaultMessage": "DNS vasitəsilə Let's Encrypt" + }, + "lets-encrypt-via-http": { + "defaultMessage": "HTTP vasitəsilə Let's Encrypt" + }, + "loading": { + "defaultMessage": "Yüklənir…" + }, + "location.advanced-config": { + "defaultMessage": "Fərdi Nginx konfiqurasiyası var" + }, + "location.filter": { + "defaultMessage": "Yol və ya təyinata görə süzgəclə" + }, + "login.2fa-code": { + "defaultMessage": "Doğrulama kodu" + }, + "login.2fa-code-placeholder": { + "defaultMessage": "Kodu daxil edin" + }, + "login.2fa-description": { + "defaultMessage": "Doğrulama tətbiqinizdəki kodu daxil edin" + }, + "login.2fa-title": { + "defaultMessage": "İkifaktorlu doğrulama" + }, + "login.2fa-verify": { + "defaultMessage": "Doğrula" + }, + "login.title": { + "defaultMessage": "Hesabınıza daxil olun" + }, + "nginx-config.label": { + "defaultMessage": "Fərdi Nginx konfiqurasiyası" + }, + "nginx-config.placeholder": { + "defaultMessage": "# Öz riskinizlə fərdi Nginx konfiqurasiyanızı bura daxil edin!" + }, + "no-permission-error": { + "defaultMessage": "Bunu görməyə icazəniz yoxdur." + }, + "notfound.action": { + "defaultMessage": "Məni əsas səhifəyə apar" + }, + "notfound.content": { + "defaultMessage": "Təəssüf ki, axtardığınız səhifə tapılmadı" + }, + "notfound.title": { + "defaultMessage": "Oops… Xəta səhifəsi tapdınız" + }, + "notification.error": { + "defaultMessage": "Xəta" + }, + "notification.object-deleted": { + "defaultMessage": "{object} silindi" + }, + "notification.object-disabled": { + "defaultMessage": "{object} deaktiv edildi" + }, + "notification.object-enabled": { + "defaultMessage": "{object} aktivləşdirildi" + }, + "notification.object-renewed": { + "defaultMessage": "{object} yeniləndi" + }, + "notification.object-saved": { + "defaultMessage": "{object} yadda saxlanıldı" + }, + "notification.success": { + "defaultMessage": "Uğurlu" + }, + "object.actions-title": { + "defaultMessage": "{object} #{id}" + }, + "object.add": { + "defaultMessage": "{object} əlavə et" + }, + "object.delete": { + "defaultMessage": "{object} sil" + }, + "object.delete.content": { + "defaultMessage": "Bu {object} silmək istədiyinizə əminsiniz?" + }, + "object.edit": { + "defaultMessage": "{object} redaktə et" + }, + "object.empty": { + "defaultMessage": "Heç bir {objects} yoxdur" + }, + "object.event.created": { + "defaultMessage": "{object} yaradıldı" + }, + "object.event.deleted": { + "defaultMessage": "{object} silindi" + }, + "object.event.disabled": { + "defaultMessage": "{object} deaktiv edildi" + }, + "object.event.enabled": { + "defaultMessage": "{object} aktivləşdirildi" + }, + "object.event.renewed": { + "defaultMessage": "{object} yeniləndi" + }, + "object.event.updated": { + "defaultMessage": "{object} yeniləndi" + }, + "offline": { + "defaultMessage": "Oflayn" + }, + "online": { + "defaultMessage": "Onlayn" + }, + "options": { + "defaultMessage": "Seçimlər" + }, + "password": { + "defaultMessage": "Parol" + }, + "password.generate": { + "defaultMessage": "Təsadüfi parol yarat" + }, + "password.hide": { + "defaultMessage": "Parolu gizlət" + }, + "password.show": { + "defaultMessage": "Parolu göstər" + }, + "permissions.hidden": { + "defaultMessage": "Gizli" + }, + "permissions.manage": { + "defaultMessage": "İdarə et" + }, + "permissions.view": { + "defaultMessage": "Yalnız baxış" + }, + "permissions.visibility.all": { + "defaultMessage": "Bütün elementlər" + }, + "permissions.visibility.title": { + "defaultMessage": "Elementin görünürlüyü" + }, + "permissions.visibility.user": { + "defaultMessage": "Yalnız yaradılan elementlər" + }, + "proxy-host": { + "defaultMessage": "Proksi host" + }, + "proxy-host.forward-host": { + "defaultMessage": "Yönləndirmə hostu / IP" + }, + "proxy-hosts": { + "defaultMessage": "Proksi hostlar" + }, + "proxy-hosts.count": { + "defaultMessage": "{count} {count, plural, one {proksi host} other {proksi host}}" + }, + "public": { + "defaultMessage": "İctimai" + }, + "redirection-host": { + "defaultMessage": "Yönləndirmə hostu" + }, + "redirection-host.forward-domain": { + "defaultMessage": "Yönləndirmə domeni" + }, + "redirection-host.forward-http-code": { + "defaultMessage": "HTTP kodu" + }, + "redirection-hosts": { + "defaultMessage": "Yönləndirmə hostları" + }, + "redirection-hosts.count": { + "defaultMessage": "{count} {count, plural, one {yönləndirmə hostu} other {yönləndirmə hostu}}" + }, + "redirection-hosts.http-code.300": { + "defaultMessage": "300 Çoxlu seçim" + }, + "redirection-hosts.http-code.301": { + "defaultMessage": "301 Daimi olaraq köçürülüb" + }, + "redirection-hosts.http-code.302": { + "defaultMessage": "302 Müvəqqəti olaraq köçürülüb" + }, + "redirection-hosts.http-code.303": { + "defaultMessage": "303 Digərinə bax" + }, + "redirection-hosts.http-code.307": { + "defaultMessage": "307 Müvəqqəti yönləndirmə" + }, + "redirection-hosts.http-code.308": { + "defaultMessage": "308 Daimi yönləndirmə" + }, + "role.admin": { + "defaultMessage": "Administrator" + }, + "role.standard-user": { + "defaultMessage": "Standart istifadəçi" + }, + "save": { + "defaultMessage": "Yadda saxla" + }, + "setting": { + "defaultMessage": "Parametr" + }, + "settings": { + "defaultMessage": "Parametrlər" + }, + "settings.default-site": { + "defaultMessage": "Standart sayt" + }, + "settings.default-site.404": { + "defaultMessage": "404 səhifəsi" + }, + "settings.default-site.444": { + "defaultMessage": "Cavab yoxdur (444)" + }, + "settings.default-site.congratulations": { + "defaultMessage": "Təbriklər səhifəsi" + }, + "settings.default-site.description": { + "defaultMessage": "Nginx naməlum Host ilə qarşılaşdıqda nə göstəriləcək" + }, + "settings.default-site.html": { + "defaultMessage": "Fərdi HTML" + }, + "settings.default-site.html.placeholder": { + "defaultMessage": "" + }, + "settings.default-site.redirect": { + "defaultMessage": "Yönləndirmə" + }, + "setup.preamble": { + "defaultMessage": "Administrator hesabınızı yaradaraq başlayın." + }, + "setup.title": { + "defaultMessage": "Xoş gəlmisiniz!" + }, + "sign-in": { + "defaultMessage": "Daxil ol" + }, + "ssl-certificate": { + "defaultMessage": "SSL sertifikatı" + }, + "stream": { + "defaultMessage": "Axın" + }, + "stream.forward-host": { + "defaultMessage": "Yönləndirmə hostu" + }, + "stream.forward-host.placeholder": { + "defaultMessage": "example.com və ya 10.0.0.1 və ya 2001:db8:3333:4444:5555:6666:7777:8888" + }, + "stream.incoming-port": { + "defaultMessage": "Daxil olan port" + }, + "streams": { + "defaultMessage": "Axınlar" + }, + "streams.count": { + "defaultMessage": "{count} {count, plural, one {axın} other {axın}}" + }, + "streams.tcp": { + "defaultMessage": "TCP" + }, + "streams.udp": { + "defaultMessage": "UDP" + }, + "test": { + "defaultMessage": "Test" + }, + "update-available": { + "defaultMessage": "Yeniləmə mövcuddur: {latestVersion}" + }, + "user": { + "defaultMessage": "İstifadəçi" + }, + "user.change-password": { + "defaultMessage": "Parolu dəyiş" + }, + "user.confirm-password": { + "defaultMessage": "Parolu təsdiqlə" + }, + "user.current-password": { + "defaultMessage": "Cari parol" + }, + "user.edit-profile": { + "defaultMessage": "Profili redaktə et" + }, + "user.full-name": { + "defaultMessage": "Tam ad" + }, + "user.login-as": { + "defaultMessage": "{name} kimi daxil ol" + }, + "user.logout": { + "defaultMessage": "Çıxış" + }, + "user.new-password": { + "defaultMessage": "Yeni parol" + }, + "user.nickname": { + "defaultMessage": "Ləqəb" + }, + "user.set-password": { + "defaultMessage": "Parolu təyin et" + }, + "user.set-permissions": { + "defaultMessage": "{name} üçün icazələri təyin et" + }, + "user.switch-dark": { + "defaultMessage": "Tünd rejimə keç" + }, + "user.switch-light": { + "defaultMessage": "Açıq rejimə keç" + }, + "user.two-factor": { + "defaultMessage": "İkifaktorlu doğrulama" + }, + "username": { + "defaultMessage": "İstifadəçi adı" + }, + "users": { + "defaultMessage": "İstifadəçilər" + } +} diff --git a/frontend/src/locale/src/de.json b/frontend/src/locale/src/de.json index f654e10858..6cdb64cf39 100644 --- a/frontend/src/locale/src/de.json +++ b/frontend/src/locale/src/de.json @@ -1,4 +1,61 @@ { + "2fa.backup-codes-remaining": { + "defaultMessage": "Verbleibende Backup-Codes: {count}" + }, + "2fa.backup-warning": { + "defaultMessage": "Bewahre diese Backup-Codes an einem sicheren Ort auf. Jeder Code kann nur einmal verwendet werden." + }, + "2fa.disable": { + "defaultMessage": "Zwei-Faktor-Authentifizierung deaktivieren" + }, + "2fa.disable-confirm": { + "defaultMessage": "2FA deaktivieren" + }, + "2fa.disable-warning": { + "defaultMessage": "Das Deaktivieren der Zwei-Faktor-Authentifizierung macht dein Konto weniger sicher." + }, + "2fa.disabled": { + "defaultMessage": "Deaktiviert" + }, + "2fa.done": { + "defaultMessage": "Ich habe meine Backup-Codes gespeichert" + }, + "2fa.enable": { + "defaultMessage": "Zwei-Faktor-Authentifizierung aktivieren" + }, + "2fa.enabled": { + "defaultMessage": "Aktiviert" + }, + "2fa.enter-code": { + "defaultMessage": "Verifizierungscode eingeben" + }, + "2fa.enter-code-disable": { + "defaultMessage": "Verifizierungscode zum Deaktivieren eingeben" + }, + "2fa.regenerate": { + "defaultMessage": "Neu generieren" + }, + "2fa.regenerate-backup": { + "defaultMessage": "Backup-Codes neu generieren" + }, + "2fa.regenerate-instructions": { + "defaultMessage": "Gib einen Verifizierungscode ein, um neue Backup-Codes zu generieren. Deine alten Codes werden dadurch ungültig." + }, + "2fa.secret-key": { + "defaultMessage": "Geheimer Schlüssel" + }, + "2fa.setup-instructions": { + "defaultMessage": "Scanne diesen QR-Code mit deiner Authenticator-App oder gib den geheimen Schlüssel manuell ein." + }, + "2fa.status": { + "defaultMessage": "Status" + }, + "2fa.title": { + "defaultMessage": "Zwei-Faktor-Authentifizierung" + }, + "2fa.verify-enable": { + "defaultMessage": "Verifizieren und aktivieren" + }, "access-list": { "defaultMessage": "Zugriffsliste" }, @@ -23,6 +80,9 @@ "access-list.public.subtitle": { "defaultMessage": "Keine Authentifizierung erforderlich" }, + "access-list.rule-source.placeholder": { + "defaultMessage": "192.168.1.100 oder 192.168.1.0/24 oder 2001:0db8::/32" + }, "access-list.satisfy-any": { "defaultMessage": "Satisfy Any" }, @@ -38,12 +98,18 @@ "action.add-location": { "defaultMessage": "Pfad hinzufügen" }, + "action.allow": { + "defaultMessage": "Erlauben" + }, "action.close": { "defaultMessage": "Schließen" }, "action.delete": { "defaultMessage": "Löschen" }, + "action.deny": { + "defaultMessage": "Verweigern" + }, "action.disable": { "defaultMessage": "Deaktivieren" }, @@ -68,6 +134,9 @@ "auditlogs": { "defaultMessage": "Protokolle" }, + "auto": { + "defaultMessage": "Automatisch" + }, "cancel": { "defaultMessage": "Abbrechen" }, @@ -128,6 +197,9 @@ "certificates.dns.provider": { "defaultMessage": "DNS Provider" }, + "certificates.dns.provider.placeholder": { + "defaultMessage": "Anbieter auswählen..." + }, "certificates.dns.warning": { "defaultMessage": "Dieser Abschnitt erfordert einige Kenntnisse über Certbot und seine DNS-Plugins. Bitte konsultieren Sie die jeweilige Plugin-Dokumentation." }, @@ -275,6 +347,9 @@ "domain-names.wildcards-not-supported": { "defaultMessage": "Wildcards werden für diese Zertifizierungsstelle nicht unterstützt." }, + "domains.advanced": { + "defaultMessage": "Erweitert" + }, "domains.force-ssl": { "defaultMessage": "Erzwinge SSL" }, @@ -287,6 +362,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Support" }, + "domains.trust-forwarded-proto": { + "defaultMessage": "Upstream Forwarded-Proto-Header vertrauen" + }, "domains.use-dns": { "defaultMessage": "Nutze DNS Challenge" }, @@ -354,7 +432,7 @@ "defaultMessage": "Pfad beibehalten" }, "host.flags.protocols": { - "defaultMessage": "Protokole" + "defaultMessage": "Protokolle" }, "host.flags.websockets-upgrade": { "defaultMessage": "Websockets Support" @@ -383,6 +461,21 @@ "loading": { "defaultMessage": "Laden…" }, + "login.2fa-code": { + "defaultMessage": "Verifizierungscode" + }, + "login.2fa-code-placeholder": { + "defaultMessage": "Code eingeben" + }, + "login.2fa-description": { + "defaultMessage": "Gib den Code aus deiner Authenticator-App ein" + }, + "login.2fa-title": { + "defaultMessage": "Zwei-Faktor-Authentifizierung" + }, + "login.2fa-verify": { + "defaultMessage": "Verifizieren" + }, "login.title": { "defaultMessage": "Anmelden" }, @@ -530,6 +623,24 @@ "redirection-hosts.count": { "defaultMessage": "{count} {count, plural, one {Redirection Host} other {Redirection Hosts}}" }, + "redirection-hosts.http-code.300": { + "defaultMessage": "300 Mehrere Auswahlmöglichkeiten" + }, + "redirection-hosts.http-code.301": { + "defaultMessage": "301 Dauerhaft verschoben" + }, + "redirection-hosts.http-code.302": { + "defaultMessage": "302 Vorübergehend verschoben" + }, + "redirection-hosts.http-code.303": { + "defaultMessage": "303 Siehe andere" + }, + "redirection-hosts.http-code.307": { + "defaultMessage": "307 Temporäre Umleitung" + }, + "redirection-hosts.http-code.308": { + "defaultMessage": "308 Permanente Umleitung" + }, "role.admin": { "defaultMessage": "Administrator" }, @@ -587,6 +698,9 @@ "stream.forward-host": { "defaultMessage": "Forward Host" }, + "stream.forward-host.placeholder": { + "defaultMessage": "example.com oder 10.0.0.1 oder 2001:db8:3333:4444:5555:6666:7777:8888" + }, "stream.incoming-port": { "defaultMessage": "Incoming Port" }, @@ -605,6 +719,9 @@ "test": { "defaultMessage": "Test" }, + "update-available": { + "defaultMessage": "Update verfügbar: {latestVersion}" + }, "user": { "defaultMessage": "User" }, @@ -647,10 +764,13 @@ "user.switch-light": { "defaultMessage": "Zum Light Mode wechseln" }, + "user.two-factor": { + "defaultMessage": "Zwei-Faktor-Auth" + }, "username": { "defaultMessage": "Benutzername" }, "users": { "defaultMessage": "Benutzer" } -} +} \ No newline at end of file diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json index bb00ac3322..11d09ea711 100644 --- a/frontend/src/locale/src/en.json +++ b/frontend/src/locale/src/en.json @@ -71,6 +71,12 @@ "access-list.help.rules-order": { "defaultMessage": "Note that the allow and deny directives will be applied in the order they are defined." }, + "access-list.inherit": { + "defaultMessage": "Inherit from Proxy Host" + }, + "access-list.inherit.subtitle": { + "defaultMessage": "Uses the proxy host's access list" + }, "access-list.pass-auth": { "defaultMessage": "Pass Auth to Upstream" }, @@ -101,6 +107,9 @@ "action.allow": { "defaultMessage": "Allow" }, + "action.clear": { + "defaultMessage": "Clear" + }, "action.close": { "defaultMessage": "Close" }, @@ -122,6 +131,9 @@ "action.enable": { "defaultMessage": "Enable" }, + "action.logs": { + "defaultMessage": "Logs" + }, "action.permissions": { "defaultMessage": "Permissions" }, @@ -266,6 +278,9 @@ "column.email": { "defaultMessage": "Email" }, + "column.error": { + "defaultMessage": "Error" + }, "column.event": { "defaultMessage": "Event" }, @@ -461,6 +476,12 @@ "loading": { "defaultMessage": "Loading…" }, + "location.advanced-config": { + "defaultMessage": "Has custom Nginx configuration" + }, + "location.filter": { + "defaultMessage": "Filter by path or destination" + }, "login.2fa-code": { "defaultMessage": "Verification Code" }, @@ -479,6 +500,51 @@ "login.title": { "defaultMessage": "Login to your account" }, + "logs": { + "defaultMessage": "Logs" + }, + "logs.channel.access": { + "defaultMessage": "Access" + }, + "logs.channel.error": { + "defaultMessage": "Error" + }, + "logs.download": { + "defaultMessage": "Download" + }, + "logs.empty": { + "defaultMessage": "No log entries yet." + }, + "logs.level": { + "defaultMessage": "Level" + }, + "logs.level.all": { + "defaultMessage": "All Levels" + }, + "logs.lines": { + "defaultMessage": "Lines" + }, + "logs.live": { + "defaultMessage": "Live" + }, + "logs.paused": { + "defaultMessage": "Paused" + }, + "logs.refresh": { + "defaultMessage": "Refresh" + }, + "logs.search-placeholder": { + "defaultMessage": "Search log…" + }, + "logs.source": { + "defaultMessage": "Source" + }, + "logs.source.system": { + "defaultMessage": "System" + }, + "logs.truncated-warning": { + "defaultMessage": "Only the most recent portion of this file is shown." + }, "nginx-config.label": { "defaultMessage": "Custom Nginx Configuration" }, diff --git a/frontend/src/locale/src/et.json b/frontend/src/locale/src/et.json index bb00ac3322..316ede752e 100644 --- a/frontend/src/locale/src/et.json +++ b/frontend/src/locale/src/et.json @@ -1,237 +1,249 @@ { "2fa.backup-codes-remaining": { - "defaultMessage": "Backup codes remaining: {count}" + "defaultMessage": "Varukoode jäänud: {count}" }, "2fa.backup-warning": { - "defaultMessage": "Save these backup codes in a secure place. Each code can only be used once." + "defaultMessage": "Pane need varukoodid kindlasse kohta tallele. Iga koodi saab kasutada ainult üks kord." }, "2fa.disable": { - "defaultMessage": "Disable Two-Factor Authentication" + "defaultMessage": "Lülita kaheastmeline autentimine välja" }, "2fa.disable-confirm": { - "defaultMessage": "Disable 2FA" + "defaultMessage": "Lülita 2FA välja" }, "2fa.disable-warning": { - "defaultMessage": "Disabling two-factor authentication will make your account less secure." + "defaultMessage": "Ilma kaheastmelise autentimiseta on konto kergemini rünnatav." }, "2fa.disabled": { - "defaultMessage": "Disabled" + "defaultMessage": "Väljas" }, "2fa.done": { - "defaultMessage": "I have saved my backup codes" + "defaultMessage": "Varukoodid on tallele pandud" }, "2fa.enable": { - "defaultMessage": "Enable Two-Factor Authentication" + "defaultMessage": "Lülita kaheastmeline autentimine sisse" }, "2fa.enabled": { - "defaultMessage": "Enabled" + "defaultMessage": "Sees" }, "2fa.enter-code": { - "defaultMessage": "Enter verification code" + "defaultMessage": "Sisesta kinnituskood" }, "2fa.enter-code-disable": { - "defaultMessage": "Enter verification code to disable" + "defaultMessage": "Sisesta kinnituskood, et välja lülitada" }, "2fa.regenerate": { - "defaultMessage": "Regenerate" + "defaultMessage": "Loo uuesti" }, "2fa.regenerate-backup": { - "defaultMessage": "Regenerate Backup Codes" + "defaultMessage": "Loo uued varukoodid" }, "2fa.regenerate-instructions": { - "defaultMessage": "Enter a verification code to generate new backup codes. Your old codes will be invalidated." + "defaultMessage": "Sisesta kinnituskood, et luua uued varukoodid. Vanad koodid muutuvad kehtetuks." }, "2fa.secret-key": { - "defaultMessage": "Secret Key" + "defaultMessage": "Salavõti" }, "2fa.setup-instructions": { - "defaultMessage": "Scan this QR code with your authenticator app, or enter the secret manually." + "defaultMessage": "Skanni QR-kood autentimisäpiga või sisesta salavõti käsitsi." }, "2fa.status": { - "defaultMessage": "Status" + "defaultMessage": "Olek" }, "2fa.title": { - "defaultMessage": "Two-Factor Authentication" + "defaultMessage": "Kaheastmeline autentimine" }, "2fa.verify-enable": { - "defaultMessage": "Verify and Enable" + "defaultMessage": "Kinnita ja lülita sisse" }, "access-list": { - "defaultMessage": "Access List" + "defaultMessage": "Juurdepääsuloend" }, "access-list.access-count": { - "defaultMessage": "{count} {count, plural, one {Rule} other {Rules}}" + "defaultMessage": "{count} {count, plural, one {reegel} other {reeglit}}" }, "access-list.auth-count": { - "defaultMessage": "{count} {count, plural, one {User} other {Users}}" + "defaultMessage": "{count} {count, plural, one {kasutaja} other {kasutajat}}" }, "access-list.help-rules-last": { - "defaultMessage": "When at least 1 rule exists, this deny all rule will be added last" + "defaultMessage": "Kui vähemalt üks reegel on olemas, lisatakse lõppu keeld kõigile ülejäänutele" }, "access-list.help.rules-order": { - "defaultMessage": "Note that the allow and deny directives will be applied in the order they are defined." + "defaultMessage": "Luba ja keela reeglid rakenduvad selles järjekorras, milles need on kirjas." + }, + "access-list.inherit": { + "defaultMessage": "Päri puhverserverilt" + }, + "access-list.inherit.subtitle": { + "defaultMessage": "Kasutab puhverserveri juurdepääsuloendit" }, "access-list.pass-auth": { - "defaultMessage": "Pass Auth to Upstream" + "defaultMessage": "Edasta autentimine sihtserverile" }, "access-list.public": { - "defaultMessage": "Publicly Accessible" + "defaultMessage": "Avalikult ligipääsetav" }, "access-list.public.subtitle": { - "defaultMessage": "No basic auth required" + "defaultMessage": "Basic-autentimist ei küsita" }, "access-list.rule-source.placeholder": { - "defaultMessage": "192.168.1.100 or 192.168.1.0/24 or 2001:0db8::/32" + "defaultMessage": "192.168.1.100 või 192.168.1.0/24 või 2001:0db8::/32" }, "access-list.satisfy-any": { - "defaultMessage": "Satisfy Any" + "defaultMessage": "Piisab ühest tingimusest" }, "access-list.subtitle": { - "defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Rule} other {Rules}} - Created: {date}" + "defaultMessage": "{users} {users, plural, one {kasutaja} other {kasutajat}}, {rules} {rules, plural, one {reegel} other {reeglit}} – loodud: {date}" }, "access-lists": { - "defaultMessage": "Access Lists" + "defaultMessage": "Juurdepääsuloendid" }, "action.add": { - "defaultMessage": "Add" + "defaultMessage": "Lisa" }, "action.add-location": { - "defaultMessage": "Add Location" + "defaultMessage": "Lisa asukoht" }, "action.allow": { - "defaultMessage": "Allow" + "defaultMessage": "Luba" + }, + "action.clear": { + "defaultMessage": "Tühjenda" }, "action.close": { - "defaultMessage": "Close" + "defaultMessage": "Sulge" }, "action.delete": { - "defaultMessage": "Delete" + "defaultMessage": "Kustuta" }, "action.deny": { - "defaultMessage": "Deny" + "defaultMessage": "Keela" }, "action.disable": { - "defaultMessage": "Disable" + "defaultMessage": "Lülita välja" }, "action.download": { - "defaultMessage": "Download" + "defaultMessage": "Laadi alla" }, "action.edit": { - "defaultMessage": "Edit" + "defaultMessage": "Muuda" }, "action.enable": { - "defaultMessage": "Enable" + "defaultMessage": "Lülita sisse" + }, + "action.logs": { + "defaultMessage": "Logid" }, "action.permissions": { - "defaultMessage": "Permissions" + "defaultMessage": "Õigused" }, "action.renew": { - "defaultMessage": "Renew" + "defaultMessage": "Uuenda" }, "action.view-details": { - "defaultMessage": "View Details" + "defaultMessage": "Vaata üksikasju" }, "auditlogs": { - "defaultMessage": "Audit Logs" + "defaultMessage": "Auditilogid" }, "auto": { - "defaultMessage": "Auto" + "defaultMessage": "Automaatne" }, "cancel": { - "defaultMessage": "Cancel" + "defaultMessage": "Tühista" }, "certificate": { - "defaultMessage": "Certificate" + "defaultMessage": "Sertifikaat" }, "certificate.custom-certificate": { - "defaultMessage": "Certificate" + "defaultMessage": "Sertifikaat" }, "certificate.custom-certificate-key": { - "defaultMessage": "Certificate Key" + "defaultMessage": "Sertifikaadi võti" }, "certificate.custom-intermediate": { - "defaultMessage": "Intermediate Certificate" + "defaultMessage": "Vahesertifikaat" }, "certificate.in-use": { - "defaultMessage": "In Use" + "defaultMessage": "Kasutusel" }, "certificate.none.subtitle": { - "defaultMessage": "No certificate assigned" + "defaultMessage": "Sertifikaati pole määratud" }, "certificate.none.subtitle.for-http": { - "defaultMessage": "This host will not use HTTPS" + "defaultMessage": "See host ei kasuta HTTPS-i" }, "certificate.none.title": { - "defaultMessage": "None" + "defaultMessage": "Puudub" }, "certificate.not-in-use": { - "defaultMessage": "Not Used" + "defaultMessage": "Ei ole kasutusel" }, "certificate.renew": { - "defaultMessage": "Renew Certificate" + "defaultMessage": "Uuenda sertifikaati" }, "certificates": { - "defaultMessage": "Certificates" + "defaultMessage": "Sertifikaadid" }, "certificates.custom": { - "defaultMessage": "Custom Certificate" + "defaultMessage": "Kohandatud sertifikaat" }, "certificates.custom.warning": { - "defaultMessage": "Key files protected with a passphrase are not supported." + "defaultMessage": "Parooliga kaitstud võtmefaile ei toetata." }, "certificates.dns.credentials": { - "defaultMessage": "Credentials File Content" + "defaultMessage": "Tunnuste faili sisu" }, "certificates.dns.credentials-note": { - "defaultMessage": "This plugin requires a configuration file containing an API token or other credentials for your provider" + "defaultMessage": "See plugin tahab seadistusfaili, kus on teenusepakkuja API token või muud tunnused" }, "certificates.dns.credentials-warning": { - "defaultMessage": "This data will be stored as plaintext in the database and in a file!" + "defaultMessage": "Need andmed jäävad andmebaasi ja faili avatekstina!" }, "certificates.dns.propagation-seconds": { - "defaultMessage": "Propagation Seconds" + "defaultMessage": "DNS-i leviku ooteaeg" }, "certificates.dns.propagation-seconds-note": { - "defaultMessage": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation." + "defaultMessage": "Jäta tühjaks, kui tahad plugina vaikeväärtust. Mitu sekundit DNS-i levikut oodata." }, "certificates.dns.provider": { - "defaultMessage": "DNS Provider" + "defaultMessage": "DNS-teenuse pakkuja" }, "certificates.dns.provider.placeholder": { - "defaultMessage": "Select a Provider..." + "defaultMessage": "Vali pakkuja..." }, "certificates.dns.warning": { - "defaultMessage": "This section requires some knowledge about Certbot and its DNS plugins. Please consult the respective plugins documentation." + "defaultMessage": "See osa eeldab Certboti ja selle DNS-pluginate tundmist. Vaata vastava plugina juhendit." }, "certificates.http.reachability-404": { - "defaultMessage": "There is a server found at this domain but it does not seem to be Nginx Proxy Manager. Please make sure your domain points to the IP where your NPM instance is running." + "defaultMessage": "Sellel domeenil on küll server, aga see ei tundu olevat Nginx Proxy Manager. Vaata, et domeen osutaks IP-le, kus NPM tegelikult töötab." }, "certificates.http.reachability-failed-to-check": { - "defaultMessage": "Failed to check the reachability due to a communication error with site24x7.com." + "defaultMessage": "Kättesaadavust ei saanud kontrollida, sest side site24x7.com-iga katkes." }, "certificates.http.reachability-not-resolved": { - "defaultMessage": "There is no server available at this domain. Please make sure your domain exists and points to the IP where your NPM instance is running and if necessary port 80 is forwarded in your router." + "defaultMessage": "Sellel domeenil ei ole serverit. Vaata, et domeen olemas oleks, osutaks NPM-i IP-le ja vajadusel oleks ruuteris avatud port 80." }, "certificates.http.reachability-ok": { - "defaultMessage": "Your server is reachable and creating certificates should be possible." + "defaultMessage": "Server on kättesaadav, sertifikaadi saab ära teha." }, "certificates.http.reachability-other": { - "defaultMessage": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running." + "defaultMessage": "Sellel domeenil on server, aga vastus tuli ootamatu koodiga {code}. Kas see on NPM? Vaata, et domeen osutaks IP-le, kus NPM töötab." }, "certificates.http.reachability-wrong-data": { - "defaultMessage": "There is a server found at this domain but it returned an unexpected data. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running." + "defaultMessage": "Sellel domeenil on server, aga vastuse sisu ei klapi. Kas see on NPM? Vaata, et domeen osutaks IP-le, kus NPM töötab." }, "certificates.http.test-results": { - "defaultMessage": "Test Results" + "defaultMessage": "Testi tulemused" }, "certificates.http.warning": { - "defaultMessage": "These domains must be already configured to point to this installation." + "defaultMessage": "Need domeenid peavad juba osutama sellele paigaldusele." }, "certificates.key-type": { - "defaultMessage": "Key Type" + "defaultMessage": "Võtme tüüp" }, "certificates.key-type-description": { - "defaultMessage": "RSA is widely compatible, ECDSA is faster and more secure but may not be supported by older systems" + "defaultMessage": "RSA klapib peaaegu kõikjale, ECDSA on kiirem ja turvalisem, aga vanemad süsteemid ei pruugi seda tunda" }, "certificates.key-type-ecdsa": { "defaultMessage": "ECDSA 256" @@ -240,475 +252,529 @@ "defaultMessage": "RSA 2048" }, "certificates.request.subtitle": { - "defaultMessage": "with Let's Encrypt" + "defaultMessage": "Let's Encryptiga" }, "certificates.request.title": { - "defaultMessage": "Request a new Certificate" + "defaultMessage": "Taotle uut sertifikaati" }, "column.access": { - "defaultMessage": "Access" + "defaultMessage": "Juurdepääs" }, "column.authorization": { - "defaultMessage": "Authorization" + "defaultMessage": "Autentimine" }, "column.authorizations": { - "defaultMessage": "Authorizations" + "defaultMessage": "Autentimised" }, "column.custom-locations": { - "defaultMessage": "Custom Locations" + "defaultMessage": "Kohandatud asukohad" }, "column.destination": { - "defaultMessage": "Destination" + "defaultMessage": "Sihtkoht" }, "column.details": { - "defaultMessage": "Details" + "defaultMessage": "Üksikasjad" }, "column.email": { - "defaultMessage": "Email" + "defaultMessage": "E-post" + }, + "column.error": { + "defaultMessage": "Viga" }, "column.event": { - "defaultMessage": "Event" + "defaultMessage": "Sündmus" }, "column.expires": { - "defaultMessage": "Expires" + "defaultMessage": "Aegub" }, "column.http-code": { - "defaultMessage": "HTTP Code" + "defaultMessage": "HTTP-kood" }, "column.incoming-port": { - "defaultMessage": "Incoming Port" + "defaultMessage": "Sisendport" }, "column.name": { - "defaultMessage": "Name" + "defaultMessage": "Nimi" }, "column.protocol": { - "defaultMessage": "Protocol" + "defaultMessage": "Protokoll" }, "column.provider": { - "defaultMessage": "Provider" + "defaultMessage": "Pakkuja" }, "column.roles": { - "defaultMessage": "Roles" + "defaultMessage": "Rollid" }, "column.rules": { - "defaultMessage": "Rules" + "defaultMessage": "Reeglid" }, "column.satisfy": { - "defaultMessage": "Satisfy" + "defaultMessage": "Tingimus" }, "column.satisfy-all": { - "defaultMessage": "All" + "defaultMessage": "Kõik" }, "column.satisfy-any": { - "defaultMessage": "Any" + "defaultMessage": "Mõni" }, "column.scheme": { - "defaultMessage": "Scheme" + "defaultMessage": "Skeem" }, "column.source": { - "defaultMessage": "Source" + "defaultMessage": "Allikas" }, "column.ssl": { "defaultMessage": "SSL" }, "column.status": { - "defaultMessage": "Status" + "defaultMessage": "Olek" }, "created-on": { - "defaultMessage": "Created: {date}" + "defaultMessage": "Loodud: {date}" }, "dashboard": { - "defaultMessage": "Dashboard" + "defaultMessage": "Töölaud" }, "dead-host": { - "defaultMessage": "404 Host" + "defaultMessage": "404-host" }, "dead-hosts": { - "defaultMessage": "404 Hosts" + "defaultMessage": "404-hostid" }, "dead-hosts.count": { - "defaultMessage": "{count} {count, plural, one {404 Host} other {404 Hosts}}" + "defaultMessage": "{count} {count, plural, one {404-host} other {404-hosti}}" }, "disabled": { - "defaultMessage": "Disabled" + "defaultMessage": "Väljas" }, "domain-names": { - "defaultMessage": "Domain Names" + "defaultMessage": "Domeeninimed" }, "domain-names.max": { - "defaultMessage": "{count} domain names maximum" + "defaultMessage": "Kuni {count} domeeninime" }, "domain-names.placeholder": { - "defaultMessage": "Start typing to add domain..." + "defaultMessage": "Kirjuta, et domeen lisada..." }, "domain-names.wildcards-not-permitted": { - "defaultMessage": "Wildcards not permitted for this type" + "defaultMessage": "Selle tüübi puhul metamärke ei saa" }, "domain-names.wildcards-not-supported": { - "defaultMessage": "Wildcards not supported for this CA" + "defaultMessage": "See CA metamärke ei toeta" }, "domains.advanced": { - "defaultMessage": "Advanced" + "defaultMessage": "Lisavalikud" }, "domains.force-ssl": { - "defaultMessage": "Force SSL" + "defaultMessage": "Sunni SSL" }, "domains.hsts-enabled": { - "defaultMessage": "HSTS Enabled" + "defaultMessage": "HSTS sees" }, "domains.hsts-subdomains": { - "defaultMessage": "HSTS Sub-domains" + "defaultMessage": "HSTS alamdomeenidel" }, "domains.http2-support": { - "defaultMessage": "HTTP/2 Support" + "defaultMessage": "HTTP/2 tugi" }, "domains.trust-forwarded-proto": { - "defaultMessage": "Trust Upstream Forwarded Proto Headers" + "defaultMessage": "Usalda sihtserveri Forwarded Proto päiseid" }, "domains.use-dns": { - "defaultMessage": "Use DNS Challenge" + "defaultMessage": "Kasuta DNS-väljakutset" }, "email-address": { - "defaultMessage": "Email address" + "defaultMessage": "E-posti aadress" }, "empty-search": { - "defaultMessage": "No results found" + "defaultMessage": "Tulemusi ei leitud" }, "empty-subtitle": { - "defaultMessage": "Why don't you create one?" + "defaultMessage": "Miks mitte üks luua?" }, "enabled": { - "defaultMessage": "Enabled" + "defaultMessage": "Sees" }, "error.access.at-least-one": { - "defaultMessage": "Either one Authorization or one Access Rule is required" + "defaultMessage": "Vaja on vähemalt ühte kasutajat või juurdepääsureeglit" }, "error.access.duplicate-usernames": { - "defaultMessage": "Authorization Usernames must be unique" + "defaultMessage": "Kasutajanimed peavad olema unikaalsed" }, "error.invalid-auth": { - "defaultMessage": "Invalid email or password" + "defaultMessage": "Vale e-post või parool" }, "error.invalid-domain": { - "defaultMessage": "Invalid domain: {domain}" + "defaultMessage": "Vigane domeen: {domain}" }, "error.invalid-email": { - "defaultMessage": "Invalid email address" + "defaultMessage": "Vigane e-posti aadress" }, "error.max-character-length": { - "defaultMessage": "Maximum length is {max} character{max, plural, one {} other {s}}" + "defaultMessage": "Maksimumpikkus on {max} {max, plural, one {tähemärk} other {tähemärki}}" }, "error.max-domains": { - "defaultMessage": "Too many domains, max is {max}" + "defaultMessage": "Liiga palju domeene, maksimum on {max}" }, "error.maximum": { - "defaultMessage": "Maximum is {max}" + "defaultMessage": "Maksimum on {max}" }, "error.min-character-length": { - "defaultMessage": "Minimum length is {min} character{min, plural, one {} other {s}}" + "defaultMessage": "Miinimumpikkus on {min} {min, plural, one {tähemärk} other {tähemärki}}" }, "error.minimum": { - "defaultMessage": "Minimum is {min}" + "defaultMessage": "Miinimum on {min}" }, "error.passwords-must-match": { - "defaultMessage": "Passwords must match" + "defaultMessage": "Paroolid peavad klappima" }, "error.required": { - "defaultMessage": "This is required" + "defaultMessage": "See on kohustuslik" }, "expires.on": { - "defaultMessage": "Expires: {date}" + "defaultMessage": "Aegub: {date}" }, "footer.github-fork": { - "defaultMessage": "Fork me on Github" + "defaultMessage": "Tee GitHubis fork" }, "host.flags.block-exploits": { - "defaultMessage": "Block Common Exploits" + "defaultMessage": "Blokeeri levinud ründed" }, "host.flags.cache-assets": { - "defaultMessage": "Cache Assets" + "defaultMessage": "Puhverda failid" }, "host.flags.preserve-path": { - "defaultMessage": "Preserve Path" + "defaultMessage": "Säilita tee" }, "host.flags.protocols": { - "defaultMessage": "Protocols" + "defaultMessage": "Protokollid" }, "host.flags.websockets-upgrade": { - "defaultMessage": "Websockets Support" + "defaultMessage": "Websocketi tugi" }, "host.forward-port": { - "defaultMessage": "Forward Port" + "defaultMessage": "Edastusport" }, "host.forward-scheme": { - "defaultMessage": "Scheme" + "defaultMessage": "Skeem" }, "hosts": { - "defaultMessage": "Hosts" + "defaultMessage": "Hostid" }, "http-only": { - "defaultMessage": "HTTP Only" + "defaultMessage": "Ainult HTTP" }, "lets-encrypt": { "defaultMessage": "Let's Encrypt" }, "lets-encrypt-via-dns": { - "defaultMessage": "Let's Encrypt via DNS" + "defaultMessage": "Let's Encrypt DNS-iga" }, "lets-encrypt-via-http": { - "defaultMessage": "Let's Encrypt via HTTP" + "defaultMessage": "Let's Encrypt HTTP-ga" }, "loading": { - "defaultMessage": "Loading…" + "defaultMessage": "Laadimine…" + }, + "location.advanced-config": { + "defaultMessage": "Kohandatud Nginx seadistus olemas" + }, + "location.filter": { + "defaultMessage": "Filtreeri tee või sihtkoha järgi" }, "login.2fa-code": { - "defaultMessage": "Verification Code" + "defaultMessage": "Kinnituskood" }, "login.2fa-code-placeholder": { - "defaultMessage": "Enter code" + "defaultMessage": "Sisesta kood" }, "login.2fa-description": { - "defaultMessage": "Enter the code from your authenticator app" + "defaultMessage": "Sisesta kood autentimisäpist" }, "login.2fa-title": { - "defaultMessage": "Two-Factor Authentication" + "defaultMessage": "Kaheastmeline autentimine" }, "login.2fa-verify": { - "defaultMessage": "Verify" + "defaultMessage": "Kinnita" }, "login.title": { - "defaultMessage": "Login to your account" + "defaultMessage": "Logi kontole sisse" + }, + "logs": { + "defaultMessage": "Logid" + }, + "logs.channel.access": { + "defaultMessage": "Juurdepääs" + }, + "logs.channel.error": { + "defaultMessage": "Viga" + }, + "logs.download": { + "defaultMessage": "Laadi alla" + }, + "logs.empty": { + "defaultMessage": "Logikirjeid pole veel." + }, + "logs.level": { + "defaultMessage": "Tase" + }, + "logs.level.all": { + "defaultMessage": "Kõik tasemed" + }, + "logs.lines": { + "defaultMessage": "Read" + }, + "logs.live": { + "defaultMessage": "Reaalajas" + }, + "logs.paused": { + "defaultMessage": "Peatatud" + }, + "logs.refresh": { + "defaultMessage": "Värskenda" + }, + "logs.search-placeholder": { + "defaultMessage": "Otsi logist…" + }, + "logs.source": { + "defaultMessage": "Allikas" + }, + "logs.source.system": { + "defaultMessage": "Süsteem" + }, + "logs.truncated-warning": { + "defaultMessage": "Kuvatakse ainult faili kõige uuem osa." }, "nginx-config.label": { - "defaultMessage": "Custom Nginx Configuration" + "defaultMessage": "Kohandatud Nginx seadistus" }, "nginx-config.placeholder": { - "defaultMessage": "# Enter your custom Nginx configuration here at your own risk!" + "defaultMessage": "# Sisesta siia oma Nginx seadistus omal vastutusel!" }, "no-permission-error": { - "defaultMessage": "You do not have access to view this." + "defaultMessage": "Selle vaatamiseks sul õigust pole." }, "notfound.action": { - "defaultMessage": "Take me home" + "defaultMessage": "Tagasi avalehele" }, "notfound.content": { - "defaultMessage": "We are sorry but the page you are looking for was not found" + "defaultMessage": "Otsitud lehte ei ole." }, "notfound.title": { - "defaultMessage": "Oops… You just found an error page" + "defaultMessage": "Oih… lehte ei leitud" }, "notification.error": { - "defaultMessage": "Error" + "defaultMessage": "Viga" }, "notification.object-deleted": { - "defaultMessage": "{object} has been deleted" + "defaultMessage": "{object} on kustutatud" }, "notification.object-disabled": { - "defaultMessage": "{object} has been disabled" + "defaultMessage": "{object} on välja lülitatud" }, "notification.object-enabled": { - "defaultMessage": "{object} has been enabled" + "defaultMessage": "{object} on sisse lülitatud" }, "notification.object-renewed": { - "defaultMessage": "{object} has been renewed" + "defaultMessage": "{object} on uuendatud" }, "notification.object-saved": { - "defaultMessage": "{object} has been saved" + "defaultMessage": "{object} on salvestatud" }, "notification.success": { - "defaultMessage": "Success" + "defaultMessage": "Korras" }, "object.actions-title": { "defaultMessage": "{object} #{id}" }, "object.add": { - "defaultMessage": "Add {object}" + "defaultMessage": "Lisa {object}" }, "object.delete": { - "defaultMessage": "Delete {object}" + "defaultMessage": "Kustuta {object}" }, "object.delete.content": { - "defaultMessage": "Are you sure you want to delete this {object}?" + "defaultMessage": "Kas oled kindel, et tahad selle kustutada: {object}?" }, "object.edit": { - "defaultMessage": "Edit {object}" + "defaultMessage": "Muuda {object}" }, "object.empty": { - "defaultMessage": "There are no {objects}" + "defaultMessage": "{objects} puuduvad" }, "object.event.created": { - "defaultMessage": "Created {object}" + "defaultMessage": "Loodud: {object}" }, "object.event.deleted": { - "defaultMessage": "Deleted {object}" + "defaultMessage": "Kustutatud: {object}" }, "object.event.disabled": { - "defaultMessage": "Disabled {object}" + "defaultMessage": "Välja lülitatud: {object}" }, "object.event.enabled": { - "defaultMessage": "Enabled {object}" + "defaultMessage": "Sisse lülitatud: {object}" }, "object.event.renewed": { - "defaultMessage": "Renewed {object}" + "defaultMessage": "Uuendatud: {object}" }, "object.event.updated": { - "defaultMessage": "Updated {object}" + "defaultMessage": "Muudetud: {object}" }, "offline": { - "defaultMessage": "Offline" + "defaultMessage": "Maas" }, "online": { - "defaultMessage": "Online" + "defaultMessage": "Töös" }, "options": { - "defaultMessage": "Options" + "defaultMessage": "Valikud" }, "password": { - "defaultMessage": "Password" + "defaultMessage": "Parool" }, "password.generate": { - "defaultMessage": "Generate random password" + "defaultMessage": "Loo juhuslik parool" }, "password.hide": { - "defaultMessage": "Hide Password" + "defaultMessage": "Peida parool" }, "password.show": { - "defaultMessage": "Show Password" + "defaultMessage": "Näita parooli" }, "permissions.hidden": { - "defaultMessage": "Hidden" + "defaultMessage": "Peidetud" }, "permissions.manage": { - "defaultMessage": "Manage" + "defaultMessage": "Halda" }, "permissions.view": { - "defaultMessage": "View Only" + "defaultMessage": "Ainult vaatamine" }, "permissions.visibility.all": { - "defaultMessage": "All Items" + "defaultMessage": "Kõik kirjed" }, "permissions.visibility.title": { - "defaultMessage": "Item Visibility" + "defaultMessage": "Kirjete nähtavus" }, "permissions.visibility.user": { - "defaultMessage": "Created Items Only" + "defaultMessage": "Ainult enda loodud" }, "proxy-host": { - "defaultMessage": "Proxy Host" + "defaultMessage": "Puhverserver" }, "proxy-host.forward-host": { - "defaultMessage": "Forward Hostname / IP" + "defaultMessage": "Edastuse hostinimi / IP" }, "proxy-hosts": { - "defaultMessage": "Proxy Hosts" + "defaultMessage": "Puhverserverid" }, "proxy-hosts.count": { - "defaultMessage": "{count} {count, plural, one {Proxy Host} other {Proxy Hosts}}" + "defaultMessage": "{count} {count, plural, one {puhverserver} other {puhverserverit}}" }, "public": { - "defaultMessage": "Public" + "defaultMessage": "Avalik" }, "redirection-host": { - "defaultMessage": "Redirection Host" + "defaultMessage": "Ümbersuunamishost" }, "redirection-host.forward-domain": { - "defaultMessage": "Forward Domain" + "defaultMessage": "Sihtkoha domeen" }, "redirection-host.forward-http-code": { - "defaultMessage": "HTTP Code" + "defaultMessage": "HTTP-kood" }, "redirection-hosts": { - "defaultMessage": "Redirection Hosts" + "defaultMessage": "Ümbersuunamishostid" }, "redirection-hosts.count": { - "defaultMessage": "{count} {count, plural, one {Redirection Host} other {Redirection Hosts}}" + "defaultMessage": "{count} {count, plural, one {ümbersuunamishost} other {ümbersuunamishosti}}" }, "redirection-hosts.http-code.300": { - "defaultMessage": "300 Multiple Choices" + "defaultMessage": "300 mitu valikut" }, "redirection-hosts.http-code.301": { - "defaultMessage": "301 Moved permanently" + "defaultMessage": "301 jäädavalt teisaldatud" }, "redirection-hosts.http-code.302": { - "defaultMessage": "302 Moved temporarily" + "defaultMessage": "302 ajutiselt teisaldatud" }, "redirection-hosts.http-code.303": { - "defaultMessage": "303 See other" + "defaultMessage": "303 vaata mujal" }, "redirection-hosts.http-code.307": { - "defaultMessage": "307 Temporary redirect" + "defaultMessage": "307 ajutine ümbersuunamine" }, "redirection-hosts.http-code.308": { - "defaultMessage": "308 Permanent redirect" + "defaultMessage": "308 jäädav ümbersuunamine" }, "role.admin": { - "defaultMessage": "Administrator" + "defaultMessage": "Administraator" }, "role.standard-user": { - "defaultMessage": "Standard User" + "defaultMessage": "Tavakasutaja" }, "save": { - "defaultMessage": "Save" + "defaultMessage": "Salvesta" }, "setting": { - "defaultMessage": "Setting" + "defaultMessage": "Seade" }, "settings": { - "defaultMessage": "Settings" + "defaultMessage": "Seaded" }, "settings.default-site": { - "defaultMessage": "Default Site" + "defaultMessage": "Vaikesait" }, "settings.default-site.404": { - "defaultMessage": "404 Page" + "defaultMessage": "404 leht" }, "settings.default-site.444": { - "defaultMessage": "No Response (444)" + "defaultMessage": "Vastuseta (444)" }, "settings.default-site.congratulations": { - "defaultMessage": "Congratulations Page" + "defaultMessage": "Õnnitlusleht" }, "settings.default-site.description": { - "defaultMessage": "What to show when Nginx is hit with an unknown Host" + "defaultMessage": "Mida näidata, kui päring tuleb tundmatule hostile" }, "settings.default-site.html": { - "defaultMessage": "Custom HTML" + "defaultMessage": "Kohandatud HTML" }, "settings.default-site.html.placeholder": { - "defaultMessage": "" + "defaultMessage": "" }, "settings.default-site.redirect": { - "defaultMessage": "Redirect" + "defaultMessage": "Ümbersuunamine" }, "setup.preamble": { - "defaultMessage": "Get started by creating your admin account." + "defaultMessage": "Alustuseks loo endale administraatori konto." }, "setup.title": { - "defaultMessage": "Welcome!" + "defaultMessage": "Tere tulemast!" }, "sign-in": { - "defaultMessage": "Sign in" + "defaultMessage": "Logi sisse" }, "ssl-certificate": { - "defaultMessage": "SSL Certificate" + "defaultMessage": "SSL-sertifikaat" }, "stream": { - "defaultMessage": "Stream" + "defaultMessage": "Voog" }, "stream.forward-host": { - "defaultMessage": "Forward Host" + "defaultMessage": "Edastuse host" }, "stream.forward-host.placeholder": { - "defaultMessage": "example.com or 10.0.0.1 or 2001:db8:3333:4444:5555:6666:7777:8888" + "defaultMessage": "example.com või 10.0.0.1 või 2001:db8:3333:4444:5555:6666:7777:8888" }, "stream.incoming-port": { - "defaultMessage": "Incoming Port" + "defaultMessage": "Sisendport" }, "streams": { - "defaultMessage": "Streams" + "defaultMessage": "Vood" }, "streams.count": { - "defaultMessage": "{count} {count, plural, one {Stream} other {Streams}}" + "defaultMessage": "{count} {count, plural, one {voog} other {voogu}}" }, "streams.tcp": { "defaultMessage": "TCP" @@ -717,60 +783,60 @@ "defaultMessage": "UDP" }, "test": { - "defaultMessage": "Test" + "defaultMessage": "Testi" }, "update-available": { - "defaultMessage": "Update Available: {latestVersion}" + "defaultMessage": "Uuendus saadaval: {latestVersion}" }, "user": { - "defaultMessage": "User" + "defaultMessage": "Kasutaja" }, "user.change-password": { - "defaultMessage": "Change Password" + "defaultMessage": "Muuda parooli" }, "user.confirm-password": { - "defaultMessage": "Confirm Password" + "defaultMessage": "Kinnita parool" }, "user.current-password": { - "defaultMessage": "Current Password" + "defaultMessage": "Praegune parool" }, "user.edit-profile": { - "defaultMessage": "Edit Profile" + "defaultMessage": "Muuda profiili" }, "user.full-name": { - "defaultMessage": "Full Name" + "defaultMessage": "Täisnimi" }, "user.login-as": { - "defaultMessage": "Sign in as {name}" + "defaultMessage": "Logi sisse kasutajana {name}" }, "user.logout": { - "defaultMessage": "Logout" + "defaultMessage": "Logi välja" }, "user.new-password": { - "defaultMessage": "New Password" + "defaultMessage": "Uus parool" }, "user.nickname": { - "defaultMessage": "Nickname" + "defaultMessage": "Hüüdnimi" }, "user.set-password": { - "defaultMessage": "Set Password" + "defaultMessage": "Määra parool" }, "user.set-permissions": { - "defaultMessage": "Set Permissions for {name}" + "defaultMessage": "Määra {name} õigused" }, "user.switch-dark": { - "defaultMessage": "Switch to Dark mode" + "defaultMessage": "Lülitu tumedale kujundusele" }, "user.switch-light": { - "defaultMessage": "Switch to Light mode" + "defaultMessage": "Lülitu heledale kujundusele" }, "user.two-factor": { - "defaultMessage": "Two-Factor Auth" + "defaultMessage": "Kaheastmeline autentimine" }, "username": { - "defaultMessage": "Username" + "defaultMessage": "Kasutajanimi" }, "users": { - "defaultMessage": "Users" + "defaultMessage": "Kasutajad" } } diff --git a/frontend/src/locale/src/fa.json b/frontend/src/locale/src/fa.json new file mode 100644 index 0000000000..2819bbc95c --- /dev/null +++ b/frontend/src/locale/src/fa.json @@ -0,0 +1,785 @@ +{ + "2fa.backup-codes-remaining": { + "defaultMessage": "کدهای پشتیبان باقی‌مانده: {count}" + }, + "2fa.backup-warning": { + "defaultMessage": "این کدهای پشتیبان را در مکانی امن ذخیره کنید. هر کد فقط یک‌بار قابل استفاده است." + }, + "2fa.disable": { + "defaultMessage": "غیرفعال کردن احراز هویت دومرحله‌ای" + }, + "2fa.disable-confirm": { + "defaultMessage": "غیرفعال کردن 2FA" + }, + "2fa.disable-warning": { + "defaultMessage": "غیرفعال کردن احراز هویت دومرحله‌ای امنیت حساب شما را کاهش می‌دهد." + }, + "2fa.disabled": { + "defaultMessage": "غیرفعال" + }, + "2fa.done": { + "defaultMessage": "کدهای پشتیبان را ذخیره کرده‌ام" + }, + "2fa.enable": { + "defaultMessage": "فعال کردن احراز هویت دومرحله‌ای" + }, + "2fa.enabled": { + "defaultMessage": "فعال" + }, + "2fa.enter-code": { + "defaultMessage": "کد تأیید را وارد کنید" + }, + "2fa.enter-code-disable": { + "defaultMessage": "برای غیرفعال‌سازی، کد تأیید را وارد کنید" + }, + "2fa.regenerate": { + "defaultMessage": "تولید مجدد" + }, + "2fa.regenerate-backup": { + "defaultMessage": "تولید مجدد کدهای پشتیبان" + }, + "2fa.regenerate-instructions": { + "defaultMessage": "برای تولید کدهای پشتیبان جدید، یک کد تأیید وارد کنید. کدهای قبلی شما باطل خواهند شد." + }, + "2fa.secret-key": { + "defaultMessage": "کلید مخفی" + }, + "2fa.setup-instructions": { + "defaultMessage": "این QR Code را با برنامهٔ احراز هویت خود اسکن کنید یا کلید مخفی را به‌صورت دستی وارد کنید." + }, + "2fa.status": { + "defaultMessage": "وضعیت" + }, + "2fa.title": { + "defaultMessage": "احراز هویت دومرحله‌ای" + }, + "2fa.verify-enable": { + "defaultMessage": "تأیید و فعال‌سازی" + }, + "access-list": { + "defaultMessage": "فهرست دسترسی" + }, + "access-list.access-count": { + "defaultMessage": "{count} {count, plural, one {قانون دسترسی} other {قانون دسترسی}}" + }, + "access-list.auth-count": { + "defaultMessage": "{count} {count, plural, one {کاربر} other {کاربر}}" + }, + "access-list.help-rules-last": { + "defaultMessage": "اگر حداقل یک قانون وجود داشته باشد، قانون «رد همه» (Deny All) در انتهای فهرست اضافه می‌شود." + }, + "access-list.help.rules-order": { + "defaultMessage": "توجه کنید که دستورهای اجازه (Allow) و رد (Deny) به همان ترتیبی که تعریف شده‌اند اعمال می‌شوند." + }, + "access-list.pass-auth": { + "defaultMessage": "ارسال اطلاعات احراز هویت به سرور بالادستی (Upstream)" + }, + "access-list.public": { + "defaultMessage": "قابل دسترسی عمومی" + }, + "access-list.public.subtitle": { + "defaultMessage": "بدون نیاز به احراز هویت پایه (Basic Auth)" + }, + "access-list.rule-source.placeholder": { + "defaultMessage": "192.168.1.100 یا 192.168.1.0/24 یا 2001:0db8::/32" + }, + "access-list.satisfy-any": { + "defaultMessage": "کافی بودن یکی از شرایط" + }, + "access-list.subtitle": { + "defaultMessage": "{users} {users, plural, one {کاربر} other {کاربر}}، {rules} {rules, plural, one {قانون دسترسی} other {قانون دسترسی}} — ایجاد: {date}" + }, + "access-lists": { + "defaultMessage": "فهرست‌های دسترسی" + }, + "action.add": { + "defaultMessage": "افزودن" + }, + "action.add-location": { + "defaultMessage": "افزودن مسیر (Location)" + }, + "action.allow": { + "defaultMessage": "اجازه" + }, + "action.clear": { + "defaultMessage": "پاک کردن" + }, + "action.close": { + "defaultMessage": "بستن" + }, + "action.delete": { + "defaultMessage": "حذف" + }, + "action.deny": { + "defaultMessage": "رد" + }, + "action.disable": { + "defaultMessage": "غیرفعال‌سازی" + }, + "action.download": { + "defaultMessage": "دانلود" + }, + "action.edit": { + "defaultMessage": "ویرایش" + }, + "action.enable": { + "defaultMessage": "فعال‌سازی" + }, + "action.permissions": { + "defaultMessage": "دسترسی‌ها" + }, + "action.renew": { + "defaultMessage": "تمدید" + }, + "action.view-details": { + "defaultMessage": "مشاهده جزئیات" + }, + "auditlogs": { + "defaultMessage": "گزارش‌های ممیزی (Audit Logs)" + }, + "auto": { + "defaultMessage": "خودکار" + }, + "cancel": { + "defaultMessage": "لغو" + }, + "certificate": { + "defaultMessage": "گواهی" + }, + "certificate.custom-certificate": { + "defaultMessage": "گواهی" + }, + "certificate.custom-certificate-key": { + "defaultMessage": "کلید خصوصی گواهی" + }, + "certificate.custom-intermediate": { + "defaultMessage": "گواهی میانی (Intermediate)" + }, + "certificate.in-use": { + "defaultMessage": "در حال استفاده" + }, + "certificate.none.subtitle": { + "defaultMessage": "هیچ گواهی‌ای اختصاص داده نشده" + }, + "certificate.none.subtitle.for-http": { + "defaultMessage": "این میزبان از HTTPS استفاده نخواهد کرد" + }, + "certificate.none.title": { + "defaultMessage": "هیچ‌کدام" + }, + "certificate.not-in-use": { + "defaultMessage": "استفاده نشده" + }, + "certificate.renew": { + "defaultMessage": "تمدید گواهی" + }, + "certificates": { + "defaultMessage": "گواهی‌ها" + }, + "certificates.custom": { + "defaultMessage": "گواهی سفارشی" + }, + "certificates.custom.warning": { + "defaultMessage": "فایل‌های کلید خصوصیِ محافظت‌شده با رمز عبور پشتیبانی نمی‌شوند." + }, + "certificates.dns.credentials": { + "defaultMessage": "محتوای فایل اعتبارنامه‌ها" + }, + "certificates.dns.credentials-note": { + "defaultMessage": "این افزونه به یک فایل پیکربندی شامل API Token یا سایر اعتبارنامه‌های ارائه‌دهندهٔ شما نیاز دارد." + }, + "certificates.dns.credentials-warning": { + "defaultMessage": "این اطلاعات به‌صورت متن ساده (Plain Text) در پایگاه داده و یک فایل ذخیره می‌شوند!" + }, + "certificates.dns.propagation-seconds": { + "defaultMessage": "زمان انتشار DNS (ثانیه)" + }, + "certificates.dns.propagation-seconds-note": { + "defaultMessage": "برای استفاده از مقدار پیش‌فرض افزونه، این فیلد را خالی بگذارید. این مقدار مدت انتظار برای انتشار DNS را برحسب ثانیه مشخص می‌کند." + }, + "certificates.dns.provider": { + "defaultMessage": "ارائه‌دهندهٔ DNS" + }, + "certificates.dns.provider.placeholder": { + "defaultMessage": "یک ارائه‌دهندهٔ DNS انتخاب کنید..." + }, + "certificates.dns.warning": { + "defaultMessage": "این بخش نیازمند آشنایی با Certbot و افزونه‌های DNS آن است. لطفاً مستندات افزونهٔ مربوطه را بررسی کنید." + }, + "certificates.http.reachability-404": { + "defaultMessage": "در این دامنه یک سرور پیدا شد، اما به نظر نمی‌رسد Nginx Proxy Manager باشد. مطمئن شوید دامنه به IP سروری اشاره می‌کند که NPM روی آن اجرا می‌شود." + }, + "certificates.http.reachability-failed-to-check": { + "defaultMessage": "بررسی دسترسی‌پذیری به‌دلیل خطای ارتباط با site24x7.com انجام نشد." + }, + "certificates.http.reachability-not-resolved": { + "defaultMessage": "هیچ سروری در این دامنه در دسترس نیست. مطمئن شوید دامنه وجود دارد، به IP سروری اشاره می‌کند که NPM روی آن اجرا می‌شود و در صورت نیاز پورت 80 روی روتر به این سرور فوروارد شده است." + }, + "certificates.http.reachability-ok": { + "defaultMessage": "سرور شما در دسترس است و صدور گواهی باید امکان‌پذیر باشد." + }, + "certificates.http.reachability-other": { + "defaultMessage": "در این دامنه یک سرور پیدا شد، اما کد وضعیت غیرمنتظرهٔ {code} را برگرداند. آیا این سرور NPM است؟ مطمئن شوید دامنه به IP سروری اشاره می‌کند که NPM روی آن اجرا می‌شود." + }, + "certificates.http.reachability-wrong-data": { + "defaultMessage": "در این دامنه یک سرور پیدا شد، اما دادهٔ غیرمنتظره‌ای برگرداند. آیا این سرور NPM است؟ مطمئن شوید دامنه به IP سروری اشاره می‌کند که NPM روی آن اجرا می‌شود." + }, + "certificates.http.test-results": { + "defaultMessage": "نتایج تست" + }, + "certificates.http.warning": { + "defaultMessage": "این دامنه‌ها باید از قبل طوری تنظیم شده باشند که به این Nginx Proxy Manager اشاره کنند." + }, + "certificates.key-type": { + "defaultMessage": "نوع کلید" + }, + "certificates.key-type-description": { + "defaultMessage": "RSA سازگاری گسترده‌تری دارد؛ ECDSA سریع‌تر و امن‌تر است، اما ممکن است در سیستم‌های قدیمی پشتیبانی نشود." + }, + "certificates.key-type-ecdsa": { + "defaultMessage": "ECDSA 256" + }, + "certificates.key-type-rsa": { + "defaultMessage": "RSA 2048" + }, + "certificates.request.subtitle": { + "defaultMessage": "از طریق Let's Encrypt" + }, + "certificates.request.title": { + "defaultMessage": "درخواست گواهی جدید" + }, + "column.access": { + "defaultMessage": "دسترسی" + }, + "column.authorization": { + "defaultMessage": "احراز هویت" + }, + "column.authorizations": { + "defaultMessage": "کاربران احراز هویت" + }, + "column.custom-locations": { + "defaultMessage": "مسیرهای سفارشی (Location)" + }, + "column.destination": { + "defaultMessage": "مقصد" + }, + "column.details": { + "defaultMessage": "جزئیات" + }, + "column.email": { + "defaultMessage": "ایمیل" + }, + "column.event": { + "defaultMessage": "رویداد" + }, + "column.expires": { + "defaultMessage": "انقضا" + }, + "column.http-code": { + "defaultMessage": "کد HTTP" + }, + "column.incoming-port": { + "defaultMessage": "پورت ورودی" + }, + "column.name": { + "defaultMessage": "نام" + }, + "column.protocol": { + "defaultMessage": "پروتکل" + }, + "column.provider": { + "defaultMessage": "ارائه‌دهنده" + }, + "column.roles": { + "defaultMessage": "نقش‌ها" + }, + "column.rules": { + "defaultMessage": "قوانین" + }, + "column.satisfy": { + "defaultMessage": "شرط دسترسی" + }, + "column.satisfy-all": { + "defaultMessage": "همهٔ شرایط" + }, + "column.satisfy-any": { + "defaultMessage": "یکی از شرایط" + }, + "column.scheme": { + "defaultMessage": "پروتکل (Scheme)" + }, + "column.source": { + "defaultMessage": "منبع" + }, + "column.ssl": { + "defaultMessage": "SSL" + }, + "column.status": { + "defaultMessage": "وضعیت" + }, + "created-on": { + "defaultMessage": "ایجاد: {date}" + }, + "dashboard": { + "defaultMessage": "داشبورد" + }, + "dead-host": { + "defaultMessage": "میزبان 404" + }, + "dead-hosts": { + "defaultMessage": "میزبان‌های 404" + }, + "dead-hosts.count": { + "defaultMessage": "{count} {count, plural, one {میزبان 404} other {میزبان 404}}" + }, + "disabled": { + "defaultMessage": "غیرفعال" + }, + "domain-names": { + "defaultMessage": "نام‌های دامنه" + }, + "domain-names.max": { + "defaultMessage": "حداکثر {count} نام دامنه" + }, + "domain-names.placeholder": { + "defaultMessage": "برای افزودن دامنه شروع به تایپ کنید..." + }, + "domain-names.wildcards-not-permitted": { + "defaultMessage": "دامنهٔ Wildcard برای این نوع مجاز نیست." + }, + "domain-names.wildcards-not-supported": { + "defaultMessage": "این مرجع صدور گواهی (CA) از دامنه‌های Wildcard پشتیبانی نمی‌کند." + }, + "domains.advanced": { + "defaultMessage": "پیشرفته" + }, + "domains.force-ssl": { + "defaultMessage": "اجبار به HTTPS" + }, + "domains.hsts-enabled": { + "defaultMessage": "فعال‌سازی HSTS" + }, + "domains.hsts-subdomains": { + "defaultMessage": "اعمال HSTS به زیردامنه‌ها" + }, + "domains.http2-support": { + "defaultMessage": "پشتیبانی از HTTP/2" + }, + "domains.trust-forwarded-proto": { + "defaultMessage": "اعتماد به هدرهای Forwarded Proto از سرور بالادستی (Upstream)" + }, + "domains.use-dns": { + "defaultMessage": "استفاده از چالش DNS (DNS Challenge)" + }, + "email-address": { + "defaultMessage": "آدرس ایمیل" + }, + "empty-search": { + "defaultMessage": "نتیجه‌ای یافت نشد" + }, + "empty-subtitle": { + "defaultMessage": "چرا یکی ایجاد نمی‌کنید؟" + }, + "enabled": { + "defaultMessage": "فعال" + }, + "error.access.at-least-one": { + "defaultMessage": "حداقل یک کاربر احراز هویت یا یک قانون دسترسی لازم است." + }, + "error.access.duplicate-usernames": { + "defaultMessage": "نام‌های کاربری بخش احراز هویت باید یکتا باشند." + }, + "error.invalid-auth": { + "defaultMessage": "ایمیل یا رمز عبور نامعتبر است" + }, + "error.invalid-domain": { + "defaultMessage": "دامنه نامعتبر: {domain}" + }, + "error.invalid-email": { + "defaultMessage": "آدرس ایمیل نامعتبر است" + }, + "error.max-character-length": { + "defaultMessage": "حداکثر طول {max} کاراکتر است" + }, + "error.max-domains": { + "defaultMessage": "تعداد دامنه‌ها بیش از حد مجاز است؛ حداکثر {max} دامنه." + }, + "error.maximum": { + "defaultMessage": "حداکثر {max} است" + }, + "error.min-character-length": { + "defaultMessage": "حداقل طول {min} کاراکتر است" + }, + "error.minimum": { + "defaultMessage": "حداقل {min} است" + }, + "error.passwords-must-match": { + "defaultMessage": "رمزهای عبور باید مطابقت داشته باشند" + }, + "error.required": { + "defaultMessage": "این فیلد الزامی است" + }, + "expires.on": { + "defaultMessage": "انقضا: {date}" + }, + "footer.github-fork": { + "defaultMessage": "Fork در GitHub" + }, + "host.flags.block-exploits": { + "defaultMessage": "مسدودسازی اکسپلویت‌های رایج" + }, + "host.flags.cache-assets": { + "defaultMessage": "کش‌کردن فایل‌های استاتیک" + }, + "host.flags.preserve-path": { + "defaultMessage": "حفظ مسیر URL" + }, + "host.flags.protocols": { + "defaultMessage": "پروتکل‌ها" + }, + "host.flags.websockets-upgrade": { + "defaultMessage": "پشتیبانی از WebSocket" + }, + "host.forward-port": { + "defaultMessage": "پورت مقصد" + }, + "host.forward-scheme": { + "defaultMessage": "پروتکل مقصد (Scheme)" + }, + "hosts": { + "defaultMessage": "میزبان‌ها" + }, + "http-only": { + "defaultMessage": "فقط HTTP" + }, + "lets-encrypt": { + "defaultMessage": "Let's Encrypt" + }, + "lets-encrypt-via-dns": { + "defaultMessage": "Let's Encrypt از طریق DNS" + }, + "lets-encrypt-via-http": { + "defaultMessage": "Let's Encrypt از طریق HTTP" + }, + "loading": { + "defaultMessage": "در حال بارگذاری…" + }, + "location.advanced-config": { + "defaultMessage": "دارای پیکربندی سفارشی Nginx" + }, + "location.filter": { + "defaultMessage": "فیلتر بر اساس مسیر یا مقصد" + }, + "login.2fa-code": { + "defaultMessage": "کد تأیید" + }, + "login.2fa-code-placeholder": { + "defaultMessage": "کد را وارد کنید" + }, + "login.2fa-description": { + "defaultMessage": "کد را از اپلیکیشن احراز هویت خود وارد کنید" + }, + "login.2fa-title": { + "defaultMessage": "احراز هویت دومرحله‌ای" + }, + "login.2fa-verify": { + "defaultMessage": "تأیید" + }, + "login.title": { + "defaultMessage": "ورود به حساب کاربری" + }, + "nginx-config.label": { + "defaultMessage": "پیکربندی سفارشی Nginx" + }, + "nginx-config.placeholder": { + "defaultMessage": "# پیکربندی سفارشی Nginx را با مسئولیت خودتان اینجا وارد کنید!" + }, + "no-permission-error": { + "defaultMessage": "شما دسترسی لازم برای مشاهده این مورد را ندارید." + }, + "notfound.action": { + "defaultMessage": "بازگشت به صفحه اصلی" + }, + "notfound.content": { + "defaultMessage": "متأسفیم، صفحه‌ای که به دنبال آن هستید یافت نشد" + }, + "notfound.title": { + "defaultMessage": "اوه… شما به یک صفحه خطا رسیدید" + }, + "notification.error": { + "defaultMessage": "خطا" + }, + "notification.object-deleted": { + "defaultMessage": "{object} حذف شد" + }, + "notification.object-disabled": { + "defaultMessage": "{object} غیرفعال شد" + }, + "notification.object-enabled": { + "defaultMessage": "{object} فعال شد" + }, + "notification.object-renewed": { + "defaultMessage": "{object} تمدید شد" + }, + "notification.object-saved": { + "defaultMessage": "{object} ذخیره شد" + }, + "notification.success": { + "defaultMessage": "موفقیت" + }, + "object.actions-title": { + "defaultMessage": "{object} #{id}" + }, + "object.add": { + "defaultMessage": "افزودن {object}" + }, + "object.delete": { + "defaultMessage": "حذف {object}" + }, + "object.delete.content": { + "defaultMessage": "آیا مطمئن هستید که می‌خواهید این {object} را حذف کنید؟" + }, + "object.edit": { + "defaultMessage": "ویرایش {object}" + }, + "object.empty": { + "defaultMessage": "هیچ {objects} وجود ندارد" + }, + "object.event.created": { + "defaultMessage": "{object} ایجاد شد" + }, + "object.event.deleted": { + "defaultMessage": "{object} حذف شد" + }, + "object.event.disabled": { + "defaultMessage": "{object} غیرفعال شد" + }, + "object.event.enabled": { + "defaultMessage": "{object} فعال شد" + }, + "object.event.renewed": { + "defaultMessage": "{object} تمدید شد" + }, + "object.event.updated": { + "defaultMessage": "{object} به‌روزرسانی شد" + }, + "offline": { + "defaultMessage": "آفلاین" + }, + "online": { + "defaultMessage": "آنلاین" + }, + "options": { + "defaultMessage": "گزینه‌ها" + }, + "password": { + "defaultMessage": "رمز عبور" + }, + "password.generate": { + "defaultMessage": "تولید رمز عبور تصادفی" + }, + "password.hide": { + "defaultMessage": "پنهان کردن رمز عبور" + }, + "password.show": { + "defaultMessage": "نمایش رمز عبور" + }, + "permissions.hidden": { + "defaultMessage": "پنهان" + }, + "permissions.manage": { + "defaultMessage": "مدیریت" + }, + "permissions.view": { + "defaultMessage": "فقط مشاهده" + }, + "permissions.visibility.all": { + "defaultMessage": "همه موارد" + }, + "permissions.visibility.title": { + "defaultMessage": "محدودهٔ نمایش موارد" + }, + "permissions.visibility.user": { + "defaultMessage": "فقط مواردی که خودتان ایجاد کرده‌اید" + }, + "proxy-host": { + "defaultMessage": "میزبان پراکسی" + }, + "proxy-host.forward-host": { + "defaultMessage": "نام میزبان / IP مقصد" + }, + "proxy-hosts": { + "defaultMessage": "میزبان‌های پراکسی" + }, + "proxy-hosts.count": { + "defaultMessage": "{count} {count, plural, one {میزبان پراکسی} other {میزبان پراکسی}}" + }, + "public": { + "defaultMessage": "عمومی" + }, + "redirection-host": { + "defaultMessage": "میزبان تغییر مسیر" + }, + "redirection-host.forward-domain": { + "defaultMessage": "دامنهٔ مقصد" + }, + "redirection-host.forward-http-code": { + "defaultMessage": "کد HTTP" + }, + "redirection-hosts": { + "defaultMessage": "میزبان‌های تغییر مسیر" + }, + "redirection-hosts.count": { + "defaultMessage": "{count} {count, plural, one {میزبان تغییر مسیر} other {میزبان تغییر مسیر}}" + }, + "redirection-hosts.http-code.300": { + "defaultMessage": "300 انتخاب‌های متعدد" + }, + "redirection-hosts.http-code.301": { + "defaultMessage": "301 انتقال دائمی" + }, + "redirection-hosts.http-code.302": { + "defaultMessage": "302 انتقال موقت" + }, + "redirection-hosts.http-code.303": { + "defaultMessage": "303 مشاهده آدرس دیگر" + }, + "redirection-hosts.http-code.307": { + "defaultMessage": "307 تغییر مسیر موقت" + }, + "redirection-hosts.http-code.308": { + "defaultMessage": "308 تغییر مسیر دائمی" + }, + "role.admin": { + "defaultMessage": "مدیر" + }, + "role.standard-user": { + "defaultMessage": "کاربر عادی" + }, + "save": { + "defaultMessage": "ذخیره" + }, + "setting": { + "defaultMessage": "تنظیم" + }, + "settings": { + "defaultMessage": "تنظیمات" + }, + "settings.default-site": { + "defaultMessage": "سایت پیش‌فرض" + }, + "settings.default-site.404": { + "defaultMessage": "صفحه 404" + }, + "settings.default-site.444": { + "defaultMessage": "بدون پاسخ (444)" + }, + "settings.default-site.congratulations": { + "defaultMessage": "صفحه تبریک" + }, + "settings.default-site.description": { + "defaultMessage": "مشخص می‌کند وقتی Nginx درخواستی با Host ناشناخته دریافت می‌کند چه چیزی نمایش داده شود." + }, + "settings.default-site.html": { + "defaultMessage": "HTML سفارشی" + }, + "settings.default-site.html.placeholder": { + "defaultMessage": "" + }, + "settings.default-site.redirect": { + "defaultMessage": "تغییر مسیر" + }, + "setup.preamble": { + "defaultMessage": "با ساختن حساب مدیر خود شروع کنید." + }, + "setup.title": { + "defaultMessage": "خوش آمدید!" + }, + "sign-in": { + "defaultMessage": "ورود" + }, + "ssl-certificate": { + "defaultMessage": "گواهی SSL" + }, + "stream": { + "defaultMessage": "استریم" + }, + "stream.forward-host": { + "defaultMessage": "نام میزبان مقصد" + }, + "stream.forward-host.placeholder": { + "defaultMessage": "example.com یا 10.0.0.1 یا 2001:db8:3333:4444:5555:6666:7777:8888" + }, + "stream.incoming-port": { + "defaultMessage": "پورت ورودی" + }, + "streams": { + "defaultMessage": "استریم‌ها" + }, + "streams.count": { + "defaultMessage": "{count} {count, plural, one {استریم} other {استریم}}" + }, + "streams.tcp": { + "defaultMessage": "TCP" + }, + "streams.udp": { + "defaultMessage": "UDP" + }, + "test": { + "defaultMessage": "تست" + }, + "update-available": { + "defaultMessage": "به‌روزرسانی موجود است: {latestVersion}" + }, + "user": { + "defaultMessage": "کاربر" + }, + "user.change-password": { + "defaultMessage": "تغییر رمز عبور" + }, + "user.confirm-password": { + "defaultMessage": "تأیید رمز عبور" + }, + "user.current-password": { + "defaultMessage": "رمز عبور فعلی" + }, + "user.edit-profile": { + "defaultMessage": "ویرایش پروفایل" + }, + "user.full-name": { + "defaultMessage": "نام کامل" + }, + "user.login-as": { + "defaultMessage": "ورود به‌عنوان {name}" + }, + "user.logout": { + "defaultMessage": "خروج" + }, + "user.new-password": { + "defaultMessage": "رمز عبور جدید" + }, + "user.nickname": { + "defaultMessage": "نام مستعار" + }, + "user.set-password": { + "defaultMessage": "تنظیم رمز عبور" + }, + "user.set-permissions": { + "defaultMessage": "تنظیم دسترسی‌ها برای {name}" + }, + "user.switch-dark": { + "defaultMessage": "تغییر به حالت تیره" + }, + "user.switch-light": { + "defaultMessage": "تغییر به حالت روشن" + }, + "user.two-factor": { + "defaultMessage": "احراز هویت دومرحله‌ای" + }, + "username": { + "defaultMessage": "نام کاربری" + }, + "users": { + "defaultMessage": "کاربران" + } +} diff --git a/frontend/src/locale/src/lang-list.json b/frontend/src/locale/src/lang-list.json index 2e7112cf48..9ba12915a4 100644 --- a/frontend/src/locale/src/lang-list.json +++ b/frontend/src/locale/src/lang-list.json @@ -64,5 +64,14 @@ }, "locale-no-NO": { "defaultMessage": "Norsk" + }, + "locale-uk-UA": { + "defaultMessage": "Українська" + }, + "locale-az-AZ": { + "defaultMessage": "Azərbaycanca" + }, + "locale-fa-IR": { + "defaultMessage": "فارسی" } } diff --git a/frontend/src/locale/src/tr.json b/frontend/src/locale/src/tr.json index 972fa895ec..6b9091ff2e 100644 --- a/frontend/src/locale/src/tr.json +++ b/frontend/src/locale/src/tr.json @@ -1,4 +1,61 @@ { + "2fa.backup-codes-remaining": { + "defaultMessage": "Kalan yedek kod: {count}" + }, + "2fa.backup-warning": { + "defaultMessage": "Bu yedek kodları güvenli bir yerde saklayın. Her kod yalnızca bir kez kullanılabilir." + }, + "2fa.disable": { + "defaultMessage": "İki Adımlı Doğrulamayı Devre Dışı Bırak" + }, + "2fa.disable-confirm": { + "defaultMessage": "2FA'yı Devre Dışı Bırak" + }, + "2fa.disable-warning": { + "defaultMessage": "İki adımlı doğrulamayı devre dışı bırakmak hesabınızın güvenliğini azaltır." + }, + "2fa.disabled": { + "defaultMessage": "Devre Dışı" + }, + "2fa.done": { + "defaultMessage": "Yedek kodlarımı kaydettim" + }, + "2fa.enable": { + "defaultMessage": "İki Adımlı Doğrulamayı Etkinleştir" + }, + "2fa.enabled": { + "defaultMessage": "Etkin" + }, + "2fa.enter-code": { + "defaultMessage": "Doğrulama kodunu girin" + }, + "2fa.enter-code-disable": { + "defaultMessage": "Devre dışı bırakmak için doğrulama kodunu girin" + }, + "2fa.regenerate": { + "defaultMessage": "Yeniden Oluştur" + }, + "2fa.regenerate-backup": { + "defaultMessage": "Yedek Kodları Yeniden Oluştur" + }, + "2fa.regenerate-instructions": { + "defaultMessage": "Yeni yedek kodlar oluşturmak için bir doğrulama kodu girin. Eski kodlarınız geçersiz olacaktır." + }, + "2fa.secret-key": { + "defaultMessage": "Gizli Anahtar" + }, + "2fa.setup-instructions": { + "defaultMessage": "Bu QR kodunu kimlik doğrulama uygulamanızla tarayın veya gizli anahtarı elle girin." + }, + "2fa.status": { + "defaultMessage": "Durum" + }, + "2fa.title": { + "defaultMessage": "İki Adımlı Doğrulama" + }, + "2fa.verify-enable": { + "defaultMessage": "Doğrula ve Etkinleştir" + }, "access-list": { "defaultMessage": "Erişim Listesi" }, @@ -44,6 +101,9 @@ "action.allow": { "defaultMessage": "İzin Ver" }, + "action.clear": { + "defaultMessage": "Temizle" + }, "action.close": { "defaultMessage": "Kapat" }, @@ -170,6 +230,18 @@ "certificates.http.warning": { "defaultMessage": "Bu alan adları zaten bu kuruluma işaret edecek şekilde yapılandırılmış olmalıdır." }, + "certificates.key-type": { + "defaultMessage": "Anahtar Türü" + }, + "certificates.key-type-description": { + "defaultMessage": "RSA yaygın olarak uyumludur; ECDSA daha hızlı ve daha güvenlidir ancak eski sistemler tarafından desteklenmeyebilir" + }, + "certificates.key-type-ecdsa": { + "defaultMessage": "ECDSA 256" + }, + "certificates.key-type-rsa": { + "defaultMessage": "RSA 2048" + }, "certificates.request.subtitle": { "defaultMessage": "Let's Encrypt ile" }, @@ -278,6 +350,9 @@ "domain-names.wildcards-not-supported": { "defaultMessage": "Bu CA için joker karakterler desteklenmiyor" }, + "domains.advanced": { + "defaultMessage": "Gelişmiş" + }, "domains.force-ssl": { "defaultMessage": "SSL'i Zorla" }, @@ -290,6 +365,9 @@ "domains.http2-support": { "defaultMessage": "HTTP/2 Desteği" }, + "domains.trust-forwarded-proto": { + "defaultMessage": "Yukarı Akıştan Gelen Forwarded Proto Başlıklarına Güven" + }, "domains.use-dns": { "defaultMessage": "DNS Challenge Kullan" }, @@ -386,6 +464,27 @@ "loading": { "defaultMessage": "Yükleniyor…" }, + "location.advanced-config": { + "defaultMessage": "Özel Nginx yapılandırması var" + }, + "location.filter": { + "defaultMessage": "Yol veya hedefe göre filtrele" + }, + "login.2fa-code": { + "defaultMessage": "Doğrulama Kodu" + }, + "login.2fa-code-placeholder": { + "defaultMessage": "Kodu girin" + }, + "login.2fa-description": { + "defaultMessage": "Kimlik doğrulama uygulamanızdaki kodu girin" + }, + "login.2fa-title": { + "defaultMessage": "İki Adımlı Doğrulama" + }, + "login.2fa-verify": { + "defaultMessage": "Doğrula" + }, "login.title": { "defaultMessage": "Hesabınıza giriş yapın" }, @@ -674,6 +773,9 @@ "user.switch-light": { "defaultMessage": "Açık moda geç" }, + "user.two-factor": { + "defaultMessage": "İki Adımlı Doğrulama" + }, "username": { "defaultMessage": "Kullanıcı Adı" }, diff --git a/frontend/src/locale/src/uk.json b/frontend/src/locale/src/uk.json new file mode 100644 index 0000000000..3508ebbb01 --- /dev/null +++ b/frontend/src/locale/src/uk.json @@ -0,0 +1,785 @@ +{ + "2fa.backup-codes-remaining": { + "defaultMessage": "Резервних кодів залишилося: {count}" + }, + "2fa.backup-warning": { + "defaultMessage": "Збережіть ці резервні коди в безпечному місці. Кожен код можна використати лише один раз." + }, + "2fa.disable": { + "defaultMessage": "Вимкнути двофакторну автентифікацію" + }, + "2fa.disable-confirm": { + "defaultMessage": "Вимкнути 2FA" + }, + "2fa.disable-warning": { + "defaultMessage": "Вимкнення двофакторної автентифікації знизить рівень безпеки вашого облікового запису." + }, + "2fa.disabled": { + "defaultMessage": "Вимкнено" + }, + "2fa.done": { + "defaultMessage": "Резервні коди збережено" + }, + "2fa.enable": { + "defaultMessage": "Увімкнути двофакторну автентифікацію" + }, + "2fa.enabled": { + "defaultMessage": "Увімкнено" + }, + "2fa.enter-code": { + "defaultMessage": "Введіть код підтвердження" + }, + "2fa.enter-code-disable": { + "defaultMessage": "Введіть код підтвердження для вимкнення" + }, + "2fa.regenerate": { + "defaultMessage": "Згенерувати повторно" + }, + "2fa.regenerate-backup": { + "defaultMessage": "Повторно згенерувати резервні коди" + }, + "2fa.regenerate-instructions": { + "defaultMessage": "Введіть код підтвердження, щоб згенерувати нові резервні коди. Ваші старі коди стануть недійсними." + }, + "2fa.secret-key": { + "defaultMessage": "Секретний ключ" + }, + "2fa.setup-instructions": { + "defaultMessage": "Відскануйте цей QR-код у застосунку-автентифікаторі або введіть секретний ключ вручну." + }, + "2fa.status": { + "defaultMessage": "Статус" + }, + "2fa.title": { + "defaultMessage": "Двофакторна автентифікація" + }, + "2fa.verify-enable": { + "defaultMessage": "Підтвердити й увімкнути" + }, + "access-list": { + "defaultMessage": "Список доступу" + }, + "access-list.access-count": { + "defaultMessage": "{count} {count, plural, one {правило} few {правила} many {правил} other {правила}}" + }, + "access-list.auth-count": { + "defaultMessage": "{count} {count, plural, one {користувач} few {користувача} many {користувачів} other {користувача}}" + }, + "access-list.help-rules-last": { + "defaultMessage": "Якщо є хоча б одне правило, правило 'заборонити все' буде додано останнім" + }, + "access-list.help.rules-order": { + "defaultMessage": "Зверніть увагу: дозволяючі та забороняючі директиви застосовуються в порядку їх визначення." + }, + "access-list.pass-auth": { + "defaultMessage": "Передавати авторизацію на upstream-сервер" + }, + "access-list.public": { + "defaultMessage": "Загальнодоступний" + }, + "access-list.public.subtitle": { + "defaultMessage": "Без аутентифікації" + }, + "access-list.rule-source.placeholder": { + "defaultMessage": "192.168.1.100 або 192.168.1.0/24 або 2001:0db8::/32" + }, + "access-list.satisfy-any": { + "defaultMessage": "Будь-який збіг" + }, + "access-list.subtitle": { + "defaultMessage": "{users} {users, plural, one {користувач} few {користувача} many {користувачів} other {користувача}}, {rules} {rules, plural, one {правило} few {правила} many {правил} other {правила}} - створено: {date}" + }, + "access-lists": { + "defaultMessage": "Списки доступу" + }, + "action.add": { + "defaultMessage": "Додати" + }, + "action.add-location": { + "defaultMessage": "Додати маршрут" + }, + "action.allow": { + "defaultMessage": "Дозволити" + }, + "action.clear": { + "defaultMessage": "Очистити" + }, + "action.close": { + "defaultMessage": "Закрити" + }, + "action.delete": { + "defaultMessage": "Видалити" + }, + "action.deny": { + "defaultMessage": "Заборонити" + }, + "action.disable": { + "defaultMessage": "Вимкнути" + }, + "action.download": { + "defaultMessage": "Завантажити" + }, + "action.edit": { + "defaultMessage": "Змінити" + }, + "action.enable": { + "defaultMessage": "Увімкнути" + }, + "action.permissions": { + "defaultMessage": "Дозволи" + }, + "action.renew": { + "defaultMessage": "Продовжити" + }, + "action.view-details": { + "defaultMessage": "Переглянути відомості" + }, + "auditlogs": { + "defaultMessage": "Журнал аудиту" + }, + "auto": { + "defaultMessage": "Автоматично" + }, + "cancel": { + "defaultMessage": "Скасувати" + }, + "certificate": { + "defaultMessage": "Сертифікат" + }, + "certificate.custom-certificate": { + "defaultMessage": "Сертифікат" + }, + "certificate.custom-certificate-key": { + "defaultMessage": "Ключ сертифіката" + }, + "certificate.custom-intermediate": { + "defaultMessage": "Проміжний сертифікат" + }, + "certificate.in-use": { + "defaultMessage": "Використовується" + }, + "certificate.none.subtitle": { + "defaultMessage": "Сертифікат не призначено" + }, + "certificate.none.subtitle.for-http": { + "defaultMessage": "Цей хост не використовуватиме HTTPS" + }, + "certificate.none.title": { + "defaultMessage": "Немає" + }, + "certificate.not-in-use": { + "defaultMessage": "Не використовується" + }, + "certificate.renew": { + "defaultMessage": "Продовжити сертифікат" + }, + "certificates": { + "defaultMessage": "Сертифікати" + }, + "certificates.custom": { + "defaultMessage": "Власний сертифікат" + }, + "certificates.custom.warning": { + "defaultMessage": "Файли ключів, захищені паролем, не підтримуються." + }, + "certificates.dns.credentials": { + "defaultMessage": "Вміст файлу облікових даних" + }, + "certificates.dns.credentials-note": { + "defaultMessage": "Цей плагін потребує файл конфігурації, що містить API-токен або інші облікові дані вашого провайдера" + }, + "certificates.dns.credentials-warning": { + "defaultMessage": "Ці дані зберігатимуться у незашифрованому вигляді в базі даних та файлі!" + }, + "certificates.dns.propagation-seconds": { + "defaultMessage": "Очікування поширення (сек.)" + }, + "certificates.dns.propagation-seconds-note": { + "defaultMessage": "Залиште порожнім для значення за замовчуванням плагіна. Секунди очікування поширення DNS." + }, + "certificates.dns.provider": { + "defaultMessage": "DNS-провайдер" + }, + "certificates.dns.provider.placeholder": { + "defaultMessage": "Виберіть провайдера…" + }, + "certificates.dns.warning": { + "defaultMessage": "Цей розділ потребує знань про Certbot та його DNS-плагіни. Будь ласка, зверніться до документації відповідних плагінів." + }, + "certificates.http.reachability-404": { + "defaultMessage": "На цьому домені знайдено сервер, але, схоже, це не Nginx Proxy Manager. Переконайтеся, що ваш домен вказує на IP-адресу, де запущено ваш екземпляр NPM." + }, + "certificates.http.reachability-failed-to-check": { + "defaultMessage": "Не вдалося перевірити доступність через помилку зв'язку з site24x7.com." + }, + "certificates.http.reachability-not-resolved": { + "defaultMessage": "На цьому домені недоступний сервер. Переконайтеся, що домен існує та вказує на IP-адресу, де запущено ваш екземпляр NPM, і за потреби порт 80 проброшено на вашому роутері." + }, + "certificates.http.reachability-ok": { + "defaultMessage": "Сервер доступний, випуск сертифікатів можливий." + }, + "certificates.http.reachability-other": { + "defaultMessage": "На цьому домені знайдено сервер, але він повернув неочікуваний статус-код {code}. Це сервер NPM? Переконайтеся, що ваш домен вказує на IP-адресу, де запущено ваш екземпляр NPM." + }, + "certificates.http.reachability-wrong-data": { + "defaultMessage": "На цьому домені знайдено сервер, але він повернув неочікувані дані. Це сервер NPM? Переконайтеся, що ваш домен вказує на IP-адресу, де запущено ваш екземпляр NPM." + }, + "certificates.http.test-results": { + "defaultMessage": "Результати перевірки" + }, + "certificates.http.warning": { + "defaultMessage": "Ці домени мають бути налаштовані та вказувати на цей екземпляр." + }, + "certificates.key-type": { + "defaultMessage": "Тип ключа" + }, + "certificates.key-type-description": { + "defaultMessage": "RSA широко сумісний, ECDSA швидший і безпечніший, але може не підтримуватися старими системами" + }, + "certificates.key-type-ecdsa": { + "defaultMessage": "ECDSA 256" + }, + "certificates.key-type-rsa": { + "defaultMessage": "RSA 2048" + }, + "certificates.request.subtitle": { + "defaultMessage": "через Let's Encrypt" + }, + "certificates.request.title": { + "defaultMessage": "Отримати новий сертифікат" + }, + "column.access": { + "defaultMessage": "Доступ" + }, + "column.authorization": { + "defaultMessage": "Авторизація" + }, + "column.authorizations": { + "defaultMessage": "Авторизації" + }, + "column.custom-locations": { + "defaultMessage": "Власні маршрути" + }, + "column.destination": { + "defaultMessage": "Призначення" + }, + "column.details": { + "defaultMessage": "Відомості" + }, + "column.email": { + "defaultMessage": "Ел. пошта" + }, + "column.event": { + "defaultMessage": "Подія" + }, + "column.expires": { + "defaultMessage": "Закінчується" + }, + "column.http-code": { + "defaultMessage": "HTTP-код" + }, + "column.incoming-port": { + "defaultMessage": "Вхідний порт" + }, + "column.name": { + "defaultMessage": "Ім'я" + }, + "column.protocol": { + "defaultMessage": "Протокол" + }, + "column.provider": { + "defaultMessage": "Провайдер" + }, + "column.roles": { + "defaultMessage": "Ролі" + }, + "column.rules": { + "defaultMessage": "Правила" + }, + "column.satisfy": { + "defaultMessage": "Умови" + }, + "column.satisfy-all": { + "defaultMessage": "Усі" + }, + "column.satisfy-any": { + "defaultMessage": "Будь-яке" + }, + "column.scheme": { + "defaultMessage": "Схема" + }, + "column.source": { + "defaultMessage": "Джерело" + }, + "column.ssl": { + "defaultMessage": "SSL" + }, + "column.status": { + "defaultMessage": "Статус" + }, + "created-on": { + "defaultMessage": "Створено: {date}" + }, + "dashboard": { + "defaultMessage": "Огляд" + }, + "dead-host": { + "defaultMessage": "404-хост" + }, + "dead-hosts": { + "defaultMessage": "404-хости" + }, + "dead-hosts.count": { + "defaultMessage": "{count} {count, plural, one {404-хост} few {404-хоста} many {404-хостів} other {404-хоста}}" + }, + "disabled": { + "defaultMessage": "Вимкнено" + }, + "domain-names": { + "defaultMessage": "Домени" + }, + "domain-names.max": { + "defaultMessage": "Максимум {count} доменів" + }, + "domain-names.placeholder": { + "defaultMessage": "Почніть вводити, щоб додати домен..." + }, + "domain-names.wildcards-not-permitted": { + "defaultMessage": "Підстановчі домени не дозволені для цього типу" + }, + "domain-names.wildcards-not-supported": { + "defaultMessage": "Підстановчі домени не підтримуються цим центром сертифікації" + }, + "domains.advanced": { + "defaultMessage": "Розширені налаштування" + }, + "domains.force-ssl": { + "defaultMessage": "Завжди SSL" + }, + "domains.hsts-enabled": { + "defaultMessage": "Підтримка HSTS" + }, + "domains.hsts-subdomains": { + "defaultMessage": "Піддомени HSTS" + }, + "domains.http2-support": { + "defaultMessage": "Підтримка HTTP/2" + }, + "domains.trust-forwarded-proto": { + "defaultMessage": "Довіряти заголовкам X-Forwarded-Proto від upstream-сервера" + }, + "domains.use-dns": { + "defaultMessage": "Перевірка через DNS" + }, + "email-address": { + "defaultMessage": "Адреса ел. пошти" + }, + "empty-search": { + "defaultMessage": "Нічого не знайдено" + }, + "empty-subtitle": { + "defaultMessage": "Чому б не створити його?" + }, + "enabled": { + "defaultMessage": "Увімкнено" + }, + "error.access.at-least-one": { + "defaultMessage": "Потрібна хоча б одна авторизація або одне правило доступу" + }, + "error.access.duplicate-usernames": { + "defaultMessage": "Імена користувачів для авторизації мають бути унікальними" + }, + "error.invalid-auth": { + "defaultMessage": "Невірна адреса ел. пошти або пароль" + }, + "error.invalid-domain": { + "defaultMessage": "Невірний домен: {domain}" + }, + "error.invalid-email": { + "defaultMessage": "Невірна адреса ел. пошти" + }, + "error.max-character-length": { + "defaultMessage": "Максимальна довжина {max} {max, plural, one {символ} few {символи} many {символів} other {символа}}" + }, + "error.max-domains": { + "defaultMessage": "Занадто багато доменів, максимум {max}" + }, + "error.maximum": { + "defaultMessage": "Максимум {max}" + }, + "error.min-character-length": { + "defaultMessage": "Мінімальна довжина {min} {min, plural, one {символ} few {символи} many {символів} other {символа}}" + }, + "error.minimum": { + "defaultMessage": "Мінімум {min}" + }, + "error.passwords-must-match": { + "defaultMessage": "Паролі повинні збігатися" + }, + "error.required": { + "defaultMessage": "Обов'язкове поле" + }, + "expires.on": { + "defaultMessage": "Закінчується: {date}" + }, + "footer.github-fork": { + "defaultMessage": "Зробити форк на GitHub" + }, + "host.flags.block-exploits": { + "defaultMessage": "Блокувати відомі експлойти" + }, + "host.flags.cache-assets": { + "defaultMessage": "Кешувати ресурси" + }, + "host.flags.preserve-path": { + "defaultMessage": "Зберігати шлях" + }, + "host.flags.protocols": { + "defaultMessage": "Протоколи" + }, + "host.flags.websockets-upgrade": { + "defaultMessage": "Підтримка WebSocket" + }, + "host.forward-port": { + "defaultMessage": "Порт перенаправлення" + }, + "host.forward-scheme": { + "defaultMessage": "Схема" + }, + "hosts": { + "defaultMessage": "Хости" + }, + "http-only": { + "defaultMessage": "Тільки HTTP" + }, + "lets-encrypt": { + "defaultMessage": "Let's Encrypt" + }, + "lets-encrypt-via-dns": { + "defaultMessage": "Let's Encrypt через DNS" + }, + "lets-encrypt-via-http": { + "defaultMessage": "Let's Encrypt через HTTP" + }, + "loading": { + "defaultMessage": "Завантаження…" + }, + "location.advanced-config": { + "defaultMessage": "Має власну конфігурацію Nginx" + }, + "location.filter": { + "defaultMessage": "Фільтрувати за шляхом або призначенням" + }, + "login.2fa-code": { + "defaultMessage": "Код підтвердження" + }, + "login.2fa-code-placeholder": { + "defaultMessage": "Введіть код" + }, + "login.2fa-description": { + "defaultMessage": "Введіть код із застосунку-автентифікатора" + }, + "login.2fa-title": { + "defaultMessage": "Двофакторна автентифікація" + }, + "login.2fa-verify": { + "defaultMessage": "Підтвердити" + }, + "login.title": { + "defaultMessage": "Авторизація" + }, + "nginx-config.label": { + "defaultMessage": "Власна Nginx-конфігурація" + }, + "nginx-config.placeholder": { + "defaultMessage": "# Введіть тут свою Nginx-конфігурацію, будьте обережні!" + }, + "no-permission-error": { + "defaultMessage": "У вас немає доступу для перегляду." + }, + "notfound.action": { + "defaultMessage": "Повернутися на головну" + }, + "notfound.content": { + "defaultMessage": "Вибачте, але сторінку, яку ви шукаєте, не знайдено" + }, + "notfound.title": { + "defaultMessage": "Ой… Ви потрапили на сторінку помилки" + }, + "notification.error": { + "defaultMessage": "Помилка" + }, + "notification.object-deleted": { + "defaultMessage": "{object} видалено" + }, + "notification.object-disabled": { + "defaultMessage": "{object} вимкнено" + }, + "notification.object-enabled": { + "defaultMessage": "{object} увімкнено" + }, + "notification.object-renewed": { + "defaultMessage": "{object} продовжено" + }, + "notification.object-saved": { + "defaultMessage": "{object} збережено" + }, + "notification.success": { + "defaultMessage": "Успішно" + }, + "object.actions-title": { + "defaultMessage": "{object} #{id}" + }, + "object.add": { + "defaultMessage": "Додати {object}" + }, + "object.delete": { + "defaultMessage": "Видалити {object}" + }, + "object.delete.content": { + "defaultMessage": "Ви впевнені, що хочете видалити {object}?" + }, + "object.edit": { + "defaultMessage": "Змінити {object}" + }, + "object.empty": { + "defaultMessage": "{objects} відсутні" + }, + "object.event.created": { + "defaultMessage": "{object} створено" + }, + "object.event.deleted": { + "defaultMessage": "{object} видалено" + }, + "object.event.disabled": { + "defaultMessage": "{object} вимкнено" + }, + "object.event.enabled": { + "defaultMessage": "{object} увімкнено" + }, + "object.event.renewed": { + "defaultMessage": "{object} продовжено" + }, + "object.event.updated": { + "defaultMessage": "{object} оновлено" + }, + "offline": { + "defaultMessage": "Офлайн" + }, + "online": { + "defaultMessage": "Онлайн" + }, + "options": { + "defaultMessage": "Параметри" + }, + "password": { + "defaultMessage": "Пароль" + }, + "password.generate": { + "defaultMessage": "Згенерувати випадковий пароль" + }, + "password.hide": { + "defaultMessage": "Сховати пароль" + }, + "password.show": { + "defaultMessage": "Показати пароль" + }, + "permissions.hidden": { + "defaultMessage": "Приховано" + }, + "permissions.manage": { + "defaultMessage": "Керування" + }, + "permissions.view": { + "defaultMessage": "Тільки перегляд" + }, + "permissions.visibility.all": { + "defaultMessage": "Усі елементи" + }, + "permissions.visibility.title": { + "defaultMessage": "Видимість елементів" + }, + "permissions.visibility.user": { + "defaultMessage": "Створені елементи" + }, + "proxy-host": { + "defaultMessage": "Проксі-хост" + }, + "proxy-host.forward-host": { + "defaultMessage": "Хост / IP перенаправлення" + }, + "proxy-hosts": { + "defaultMessage": "Проксі-хости" + }, + "proxy-hosts.count": { + "defaultMessage": "{count} {count, plural, one {проксі-хост} few {проксі-хоста} many {проксі-хостів} other {проксі-хоста}}" + }, + "public": { + "defaultMessage": "Загальнодоступний" + }, + "redirection-host": { + "defaultMessage": "Редирект-хост" + }, + "redirection-host.forward-domain": { + "defaultMessage": "Домен перенаправлення" + }, + "redirection-host.forward-http-code": { + "defaultMessage": "HTTP-код" + }, + "redirection-hosts": { + "defaultMessage": "Редирект-хости" + }, + "redirection-hosts.count": { + "defaultMessage": "{count} {count, plural, one {редирект-хост} few {редирект-хоста} many {редирект-хостів} other {редирект-хоста}}" + }, + "redirection-hosts.http-code.300": { + "defaultMessage": "300 Кілька варіантів" + }, + "redirection-hosts.http-code.301": { + "defaultMessage": "301 Переміщено назавжди" + }, + "redirection-hosts.http-code.302": { + "defaultMessage": "302 Тимчасово переміщено" + }, + "redirection-hosts.http-code.303": { + "defaultMessage": "303 Переглянути інше" + }, + "redirection-hosts.http-code.307": { + "defaultMessage": "307 Тимчасове перенаправлення" + }, + "redirection-hosts.http-code.308": { + "defaultMessage": "308 Постійне перенаправлення" + }, + "role.admin": { + "defaultMessage": "Адміністратор" + }, + "role.standard-user": { + "defaultMessage": "Звичайний користувач" + }, + "save": { + "defaultMessage": "Зберегти" + }, + "setting": { + "defaultMessage": "Налаштування" + }, + "settings": { + "defaultMessage": "Налаштування" + }, + "settings.default-site": { + "defaultMessage": "Сторінка за замовчуванням" + }, + "settings.default-site.404": { + "defaultMessage": "404-сторінка" + }, + "settings.default-site.444": { + "defaultMessage": "Немає відповіді (444)" + }, + "settings.default-site.congratulations": { + "defaultMessage": "Сторінка привітання" + }, + "settings.default-site.description": { + "defaultMessage": "Що показувати, коли Nginx отримує невідомий хост" + }, + "settings.default-site.html": { + "defaultMessage": "Власний HTML" + }, + "settings.default-site.html.placeholder": { + "defaultMessage": "" + }, + "settings.default-site.redirect": { + "defaultMessage": "Перенаправлення" + }, + "setup.preamble": { + "defaultMessage": "Почніть із створення облікового запису адміністратора." + }, + "setup.title": { + "defaultMessage": "Ласкаво просимо!" + }, + "sign-in": { + "defaultMessage": "Увійти" + }, + "ssl-certificate": { + "defaultMessage": "SSL-сертифікат" + }, + "stream": { + "defaultMessage": "Потік" + }, + "stream.forward-host": { + "defaultMessage": "Хост перенаправлення" + }, + "stream.forward-host.placeholder": { + "defaultMessage": "example.com або 10.0.0.1 або 2001:db8:3333:4444:5555:6666:7777:8888" + }, + "stream.incoming-port": { + "defaultMessage": "Вхідний порт" + }, + "streams": { + "defaultMessage": "Потоки" + }, + "streams.count": { + "defaultMessage": "{count} {count, plural, one {потік} few {потоки} many {потоків} other {потока}}" + }, + "streams.tcp": { + "defaultMessage": "TCP" + }, + "streams.udp": { + "defaultMessage": "UDP" + }, + "test": { + "defaultMessage": "Перевірити" + }, + "update-available": { + "defaultMessage": "Доступне оновлення: {latestVersion}" + }, + "user": { + "defaultMessage": "Користувач" + }, + "user.change-password": { + "defaultMessage": "Змінити пароль" + }, + "user.confirm-password": { + "defaultMessage": "Повторіть пароль" + }, + "user.current-password": { + "defaultMessage": "Поточний пароль" + }, + "user.edit-profile": { + "defaultMessage": "Змінити профіль" + }, + "user.full-name": { + "defaultMessage": "Повне ім'я" + }, + "user.login-as": { + "defaultMessage": "Увійти як {name}" + }, + "user.logout": { + "defaultMessage": "Вийти" + }, + "user.new-password": { + "defaultMessage": "Новий пароль" + }, + "user.nickname": { + "defaultMessage": "Псевдонім" + }, + "user.set-password": { + "defaultMessage": "Задати пароль" + }, + "user.set-permissions": { + "defaultMessage": "Задати дозволи для {name}" + }, + "user.switch-dark": { + "defaultMessage": "Увімкнути темну тему" + }, + "user.switch-light": { + "defaultMessage": "Увімкнути світлу тему" + }, + "user.two-factor": { + "defaultMessage": "Двофакторна автентифікація" + }, + "username": { + "defaultMessage": "Ім'я користувача" + }, + "users": { + "defaultMessage": "Користувачі" + } +} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 62c1c48103..f448d547cb 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,13 +1,21 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "src/App.tsx"; +import { getLocale, isRTLLocale } from "src/locale"; -import "@tabler/core/dist/css/tabler.min.css"; import "@tabler/core/dist/js/tabler.min.js"; import "./App.css"; -ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - - - , -); +const renderApp = () => { + ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( + + + , + ); +}; + +const tablerStyles = isRTLLocale(getLocale()) + ? import("@tabler/core/dist/css/tabler.rtl.min.css") + : import("@tabler/core/dist/css/tabler.min.css"); + +void tablerStyles.then(renderApp); diff --git a/frontend/src/modals/DNSCertificateModal.tsx b/frontend/src/modals/DNSCertificateModal.tsx index f062e24dea..bca8df8d3d 100644 --- a/frontend/src/modals/DNSCertificateModal.tsx +++ b/frontend/src/modals/DNSCertificateModal.tsx @@ -70,11 +70,7 @@ const DNSCertificateModal = EasyModal.create(({ visible, remove }: InnerModalPro - diff --git a/frontend/src/modals/HTTPCertificateModal.tsx b/frontend/src/modals/HTTPCertificateModal.tsx index a06df2c62d..d7ec75190c 100644 --- a/frontend/src/modals/HTTPCertificateModal.tsx +++ b/frontend/src/modals/HTTPCertificateModal.tsx @@ -151,11 +151,7 @@ const HTTPCertificateModal = EasyModal.create(({ visible, remove }: InnerModalPr - diff --git a/frontend/src/modals/HostLogsModal.tsx b/frontend/src/modals/HostLogsModal.tsx new file mode 100644 index 0000000000..a0df04ee71 --- /dev/null +++ b/frontend/src/modals/HostLogsModal.tsx @@ -0,0 +1,93 @@ +import CodeEditor from "@uiw/react-textarea-code-editor"; +import EasyModal, { type InnerModalProps } from "ez-modal-react"; +import { useState } from "react"; +import { Alert } from "react-bootstrap"; +import Modal from "react-bootstrap/Modal"; +import { Button, Loading } from "src/components"; +import { useProxyHostLogs } from "src/hooks"; +import { T } from "src/locale"; + +const showHostLogsModal = (id: number) => { + EasyModal.show(HostLogsModal, { id }); +}; + +interface Props extends InnerModalProps { + id: number; +} +const HostLogsModal = EasyModal.create(({ id, visible, remove }: Props) => { + const [logType, setLogType] = useState<"access" | "error">("access"); + const { data, isLoading, error } = useProxyHostLogs(id, logType); + + return ( + + {!isLoading && error && ( + + {error?.message || "Unknown error"} + + )} + + + + + + + + {isLoading ? ( + + ) : ( +
+ +
+ )} +
+ + + +
+ ); +}); + +export { showHostLogsModal }; diff --git a/frontend/src/modals/RedirectionHostModal.tsx b/frontend/src/modals/RedirectionHostModal.tsx index 1bd7877f4f..9a0d95ce89 100644 --- a/frontend/src/modals/RedirectionHostModal.tsx +++ b/frontend/src/modals/RedirectionHostModal.tsx @@ -162,7 +162,9 @@ const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) = required {...field} > - + @@ -224,12 +226,24 @@ const RedirectionHostModal = EasyModal.create(({ id, visible, remove }: Props) = required {...field} > - - - - - - + + + + + + {form.errors.forwardHttpCode ? (
diff --git a/frontend/src/modals/StreamModal.tsx b/frontend/src/modals/StreamModal.tsx index 6d55348896..b87a259c47 100644 --- a/frontend/src/modals/StreamModal.tsx +++ b/frontend/src/modals/StreamModal.tsx @@ -154,7 +154,9 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => { type="text" className={`form-control ${form.errors.forwardingHost && form.touched.forwardingHost ? "is-invalid" : ""}`} required - placeholder={intl.formatMessage({ id: "stream.forward-host.placeholder" })} + placeholder={intl.formatMessage({ + id: "stream.forward-host.placeholder", + })} {...field} /> {form.errors.forwardingHost ? ( diff --git a/frontend/src/modals/TwoFactorModal.module.css b/frontend/src/modals/TwoFactorModal.module.css new file mode 100644 index 0000000000..4a559c5f8c --- /dev/null +++ b/frontend/src/modals/TwoFactorModal.module.css @@ -0,0 +1,5 @@ +.qrcode { + max-width: "200px"; + height: "auto"; + border: 6px solid #fff; +} diff --git a/frontend/src/modals/TwoFactorModal.tsx b/frontend/src/modals/TwoFactorModal.tsx index b5dd480c30..aa76d598c3 100644 --- a/frontend/src/modals/TwoFactorModal.tsx +++ b/frontend/src/modals/TwoFactorModal.tsx @@ -3,16 +3,12 @@ import { Field, Form, Formik } from "formik"; import { type ReactNode, useCallback, useEffect, useState } from "react"; import { Alert } from "react-bootstrap"; import Modal from "react-bootstrap/Modal"; -import { - disable2FA, - enable2FA, - get2FAStatus, - regenerateBackupCodes, - start2FASetup, -} from "src/api/backend"; +import QRCode from "react-qr-code"; +import { disable2FA, enable2FA, get2FAStatus, regenerateBackupCodes, start2FASetup } from "src/api/backend"; import { Button } from "src/components"; import { T } from "src/locale"; import { validateString } from "src/modules/Validations"; +import styles from "./TwoFactorModal.module.css"; type Step = "loading" | "status" | "setup" | "verify" | "backup" | "disable"; @@ -137,12 +133,7 @@ const TwoFactorModal = EasyModal.create(({ id, visible, remove }: Props) => { )}
{!isEnabled ? ( - ) : ( @@ -166,12 +157,7 @@ const TwoFactorModal = EasyModal.create(({ id, visible, remove }: Props) => {

- QR Code +
-
- {twoFactorChallenge ? : } -
+
{twoFactorChallenge ? : }
{getVersion()}
diff --git a/frontend/src/pages/Logs/LogLines.tsx b/frontend/src/pages/Logs/LogLines.tsx new file mode 100644 index 0000000000..7e1d4763ca --- /dev/null +++ b/frontend/src/pages/Logs/LogLines.tsx @@ -0,0 +1,76 @@ +import cn from "classnames"; +import { useEffect, useRef } from "react"; +import { T } from "src/locale"; +import styles from "./LogViewer.module.css"; + +const LEVEL_PATTERN = /\b(ERROR|FATAL|WARN|SUCCESS|COMPLETE|DEBUG|INFO)\b/; + +const levelClassName = (line: string): string | undefined => { + const match = line.match(LEVEL_PATTERN); + if (!match) { + return undefined; + } + switch (match[1]) { + case "ERROR": + case "FATAL": + return "text-danger"; + case "WARN": + return "text-warning"; + case "SUCCESS": + case "COMPLETE": + return "text-success"; + case "DEBUG": + return "text-secondary"; + default: + return undefined; + } +}; + +// How close to the bottom (in pixels) the user has to be for auto-scroll to keep +// following new lines. Scrolling further up than this to read history disables it, +// so newly polled lines never yank the viewport away from what's being read. +const AUTO_SCROLL_THRESHOLD_PX = 40; + +interface Props { + lines: string[]; +} + +export default function LogLines({ lines }: Props) { + const containerRef = useRef(null); + const stickToBottomRef = useRef(true); + + const handleScroll = () => { + const el = containerRef.current; + if (!el) { + return; + } + const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight; + stickToBottomRef.current = distanceFromBottom < AUTO_SCROLL_THRESHOLD_PX; + }; + + // biome-ignore lint/correctness/useExhaustiveDependencies: lines is a re-scroll trigger, not read in the body + useEffect(() => { + const el = containerRef.current; + if (el && stickToBottomRef.current) { + el.scrollTop = el.scrollHeight; + } + }, [lines]); + + if (!lines.length) { + return ( +
+ +
+ ); + } + + return ( +
+			{lines.map((line, idx) => (
+				
+					{line}
+				
+			))}
+		
+ ); +} diff --git a/frontend/src/pages/Logs/LogViewer.module.css b/frontend/src/pages/Logs/LogViewer.module.css new file mode 100644 index 0000000000..09cb1c88cf --- /dev/null +++ b/frontend/src/pages/Logs/LogViewer.module.css @@ -0,0 +1,15 @@ +.logBox { + height: 65vh; + overflow-y: auto; + padding: 0.75rem 1rem; + margin: 0; + font-family: var(--tblr-font-monospace, ui-monospace, monospace); + font-size: 0.8125rem; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-all; +} + +.logLine { + display: block; +} diff --git a/frontend/src/pages/Logs/LogViewer.tsx b/frontend/src/pages/Logs/LogViewer.tsx new file mode 100644 index 0000000000..728420c129 --- /dev/null +++ b/frontend/src/pages/Logs/LogViewer.tsx @@ -0,0 +1,249 @@ +import { useEffect, useMemo, useState } from "react"; +import Alert from "react-bootstrap/Alert"; +import type { LogChannel, LogHostType, LogSourceType } from "src/api/backend"; +import { Loading } from "src/components"; +import { useLogSources, useLogTail } from "src/hooks"; +import { T, intl } from "src/locale"; +import LogLines from "./LogLines"; + +const LINES_OPTIONS = [100, 200, 500, 1000]; +const LEVEL_OPTIONS = ["INFO", "WARN", "ERROR", "DEBUG", "SUCCESS", "FATAL", "COMPLETE"]; +const SEARCH_DEBOUNCE_MS = 300; + +const HOST_TYPES: { type: LogHostType; labelId: string }[] = [ + { type: "proxy", labelId: "proxy-hosts" }, + { type: "redirection", labelId: "redirection-hosts" }, + { type: "dead", labelId: "dead-hosts" }, + { type: "stream", labelId: "streams" }, +]; + +interface Selection { + type: LogSourceType; + hostType?: LogHostType; + hostId?: number; +} + +const encodeSelection = (selection: Selection): string => { + if (selection.type === "host") { + return `host:${selection.hostType}:${selection.hostId}`; + } + return selection.type; +}; + +const decodeSelection = (value: string): Selection => { + if (value === "system" || value === "letsencrypt") { + return { type: value }; + } + const [, hostType, hostId] = value.split(":"); + return { type: "host", hostType: hostType as LogHostType, hostId: Number(hostId) }; +}; + +const formatBytes = (bytes: number): string => { + if (bytes < 1024) { + return `${bytes} B`; + } + const units = ["KB", "MB", "GB"]; + let value = bytes / 1024; + let unitIndex = 0; + while (value >= 1024 && unitIndex < units.length - 1) { + value /= 1024; + unitIndex++; + } + return `${value.toFixed(1)} ${units[unitIndex]}`; +}; + +export default function LogViewer() { + const sourcesQuery = useLogSources(); + + const [selection, setSelection] = useState({ type: "system" }); + const [channel, setChannel] = useState("access"); + const [level, setLevel] = useState(""); + const [lines, setLines] = useState(LINES_OPTIONS[1]); + const [live, setLive] = useState(true); + const [searchInput, setSearchInput] = useState(""); + const [search, setSearch] = useState(""); + + useEffect(() => { + const handle = setTimeout(() => setSearch(searchInput.trim()), SEARCH_DEBOUNCE_MS); + return () => clearTimeout(handle); + }, [searchInput]); + + const tailQuery = useLogTail({ + type: selection.type, + hostType: selection.hostType, + hostId: selection.hostId, + channel: selection.type === "host" ? channel : undefined, + lines, + level: selection.type === "system" && level ? level : undefined, + search: search || undefined, + live, + }); + + const hostGroups = useMemo(() => { + if (!sourcesQuery.data) { + return []; + } + return HOST_TYPES.map(({ type, labelId }) => ({ + type, + labelId, + options: sourcesQuery.data.hosts[type] || [], + })).filter((group) => group.options.length > 0); + }, [sourcesQuery.data]); + + const handleDownload = () => { + const content = (tailQuery.data?.lines || []).join("\n"); + const blob = new Blob([content], { type: "text/plain" }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${encodeSelection(selection).replace(/:/g, "-")}.log`; + a.click(); + window.URL.revokeObjectURL(url); + }; + + return ( +
+
+
+
+
+

+ +

+
+ {typeof tailQuery.data?.size === "number" && ( +
+ {formatBytes(tailQuery.data.size)} +
+ )} +
+ +
+ {selection.type === "host" && ( +
+
+ + +
+
+ )} + {selection.type === "system" && ( +
+ +
+ )} +
+ setSearchInput(e.target.value)} + /> +
+
+ +
+
+ + + +
+
+
+ + {tailQuery.isError && ( +
+ {tailQuery.error?.message || "Unknown error"} +
+ )} + + {tailQuery.data?.truncated && ( +
+ + + +
+ )} + + {sourcesQuery.isLoading || (tailQuery.isLoading && !tailQuery.data) ? ( +
+ +
+ ) : ( + + )} +
+ ); +} diff --git a/frontend/src/pages/Logs/index.tsx b/frontend/src/pages/Logs/index.tsx new file mode 100644 index 0000000000..eb72b8e112 --- /dev/null +++ b/frontend/src/pages/Logs/index.tsx @@ -0,0 +1,13 @@ +import { HasPermission } from "src/components"; +import { ADMIN, VIEW } from "src/modules/Permissions"; +import LogViewer from "./LogViewer"; + +const Logs = () => { + return ( + + + + ); +}; + +export default Logs; diff --git a/frontend/src/pages/Nginx/DeadHosts/Table.tsx b/frontend/src/pages/Nginx/DeadHosts/Table.tsx index 17143e7504..e5c1b184f0 100644 --- a/frontend/src/pages/Nginx/DeadHosts/Table.tsx +++ b/frontend/src/pages/Nginx/DeadHosts/Table.tsx @@ -1,11 +1,5 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; -import { - createColumnHelper, - getCoreRowModel, - getSortedRowModel, - type SortingState, - useReactTable, -} from "@tanstack/react-table"; +import { createColumnHelper, type SortingState, useTable } from "@tanstack/react-table"; import { useMemo, useState } from "react"; import type { DeadHost } from "src/api/backend"; import { @@ -16,6 +10,7 @@ import { HasPermission, TrueFalseFormatter, } from "src/components"; +import { type Features, features } from "src/components/Table/features"; import { TableLayout } from "src/components/Table/TableLayout"; import { intl, T } from "src/locale"; import { DEAD_HOSTS, MANAGE } from "src/modules/Permissions"; @@ -30,7 +25,7 @@ interface Props { onNew?: () => void; } export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew, isFiltered }: Props) { - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); const columns = useMemo( () => [ columnHelper.accessor((row: any) => row.owner, { @@ -47,7 +42,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog columnHelper.accessor((row: any) => row, { id: "domainNames", header: intl.formatMessage({ id: "column.source" }), - sortingFn: (a, b) => { + sortFn: (a, b) => { const aVal = a.original.domainNames?.[0] ?? ""; const bVal = b.original.domainNames?.[0] ?? ""; return aVal.localeCompare(bVal); @@ -143,14 +138,12 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog const [sorting, setSorting] = useState([]); - const tableInstance = useReactTable({ + const tableInstance = useTable({ + features, columns, data, state: { sorting }, onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - rowCount: data.length, meta: { isFetching, }, diff --git a/frontend/src/pages/Nginx/ProxyHosts/Table.tsx b/frontend/src/pages/Nginx/ProxyHosts/Table.tsx index 5af58081ad..7a9b4cd6b2 100644 --- a/frontend/src/pages/Nginx/ProxyHosts/Table.tsx +++ b/frontend/src/pages/Nginx/ProxyHosts/Table.tsx @@ -1,11 +1,5 @@ -import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; -import { - createColumnHelper, - getCoreRowModel, - getSortedRowModel, - type SortingState, - useReactTable, -} from "@tanstack/react-table"; +import { IconDotsVertical, IconEdit, IconFileText, IconPower, IconTrash } from "@tabler/icons-react"; +import { createColumnHelper, type SortingState, useTable } from "@tanstack/react-table"; import { useMemo, useState } from "react"; import type { ProxyHost } from "src/api/backend"; import { @@ -17,6 +11,7 @@ import { HasPermission, TrueFalseFormatter, } from "src/components"; +import { type Features, features } from "src/components/Table/features"; import { TableLayout } from "src/components/Table/TableLayout"; import { intl, T } from "src/locale"; import { MANAGE, PROXY_HOSTS } from "src/modules/Permissions"; @@ -28,10 +23,20 @@ interface Props { onEdit?: (id: number) => void; onDelete?: (id: number) => void; onDisableToggle?: (id: number, enabled: boolean) => void; + onLogs?: (id: number) => void; onNew?: () => void; } -export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew, isFiltered }: Props) { - const columnHelper = createColumnHelper(); +export default function Table({ + data, + isFetching, + onEdit, + onDelete, + onDisableToggle, + onLogs, + onNew, + isFiltered, +}: Props) { + const columnHelper = createColumnHelper(); const columns = useMemo( () => [ columnHelper.accessor((row: any) => row.owner, { @@ -48,7 +53,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog columnHelper.accessor((row: any) => row, { id: "domainNames", header: intl.formatMessage({ id: "column.source" }), - sortingFn: (a, b) => { + sortFn: (a, b) => { const aVal = a.original.domainNames?.[0] ?? ""; const bVal = b.original.domainNames?.[0] ?? ""; return aVal.localeCompare(bVal); @@ -61,7 +66,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog columnHelper.accessor((row: any) => row, { id: "forwardHost", header: intl.formatMessage({ id: "column.destination" }), - sortingFn: (a, b) => { + sortFn: (a, b) => { const aVal = `${a.original.forwardHost}:${a.original.forwardPort}`; const bVal = `${b.original.forwardHost}:${b.original.forwardPort}`; return aVal.localeCompare(bVal); @@ -127,6 +132,17 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog + { + e.preventDefault(); + onLogs?.(info.row.original.id); + }} + > + + + ([]); - const tableInstance = useReactTable({ + const tableInstance = useTable({ + features, columns, data, state: { sorting }, onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - rowCount: data.length, meta: { isFetching, }, diff --git a/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx b/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx index 5d6602e2db..7845fb029b 100644 --- a/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx +++ b/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx @@ -6,7 +6,7 @@ import { deleteProxyHost, toggleProxyHost } from "src/api/backend"; import { Button, HasPermission, LoadingPage } from "src/components"; import { useProxyHosts } from "src/hooks"; import { T } from "src/locale"; -import { showDeleteConfirmModal, showHelpModal, showProxyHostModal } from "src/modals"; +import { showDeleteConfirmModal, showHelpModal, showHostLogsModal, showProxyHostModal } from "src/modals"; import { MANAGE, PROXY_HOSTS } from "src/modules/Permissions"; import { showObjectSuccess } from "src/notifications"; import Table from "./Table"; @@ -99,6 +99,7 @@ export default function TableWrapper() { isFiltered={!!search} isFetching={isFetching} onEdit={(id: number) => showProxyHostModal(id)} + onLogs={(id: number) => showHostLogsModal(id)} onDelete={(id: number) => { const host = data?.find((h) => h.id === id); showDeleteConfirmModal({ diff --git a/frontend/src/pages/Nginx/RedirectionHosts/Table.tsx b/frontend/src/pages/Nginx/RedirectionHosts/Table.tsx index 8e2d90f555..2457a47380 100644 --- a/frontend/src/pages/Nginx/RedirectionHosts/Table.tsx +++ b/frontend/src/pages/Nginx/RedirectionHosts/Table.tsx @@ -1,11 +1,5 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; -import { - createColumnHelper, - getCoreRowModel, - getSortedRowModel, - type SortingState, - useReactTable, -} from "@tanstack/react-table"; +import { createColumnHelper, type SortingState, useTable } from "@tanstack/react-table"; import { useMemo, useState } from "react"; import type { RedirectionHost } from "src/api/backend"; import { @@ -16,6 +10,7 @@ import { HasPermission, TrueFalseFormatter, } from "src/components"; +import { type Features, features } from "src/components/Table/features"; import { TableLayout } from "src/components/Table/TableLayout"; import { intl, T } from "src/locale"; import { MANAGE, REDIRECTION_HOSTS } from "src/modules/Permissions"; @@ -30,7 +25,7 @@ interface Props { onNew?: () => void; } export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew, isFiltered }: Props) { - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); const columns = useMemo( () => [ columnHelper.accessor((row: any) => row.owner, { @@ -47,7 +42,7 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog columnHelper.accessor((row: any) => row, { id: "domainNames", header: intl.formatMessage({ id: "column.source" }), - sortingFn: (a, b) => { + sortFn: (a, b) => { const aVal = a.original.domainNames?.[0] ?? ""; const bVal = b.original.domainNames?.[0] ?? ""; return aVal.localeCompare(bVal); @@ -164,14 +159,12 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog const [sorting, setSorting] = useState([]); - const tableInstance = useReactTable({ + const tableInstance = useTable({ + features, columns, data, state: { sorting }, onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - rowCount: data.length, meta: { isFetching, }, diff --git a/frontend/src/pages/Nginx/Streams/Table.tsx b/frontend/src/pages/Nginx/Streams/Table.tsx index 341317bf45..ec181b2095 100644 --- a/frontend/src/pages/Nginx/Streams/Table.tsx +++ b/frontend/src/pages/Nginx/Streams/Table.tsx @@ -1,11 +1,5 @@ import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; -import { - createColumnHelper, - getCoreRowModel, - getSortedRowModel, - type SortingState, - useReactTable, -} from "@tanstack/react-table"; +import { createColumnHelper, type SortingState, useTable } from "@tanstack/react-table"; import { useMemo, useState } from "react"; import type { Stream } from "src/api/backend"; import { @@ -16,6 +10,7 @@ import { TrueFalseFormatter, ValueWithDateFormatter, } from "src/components"; +import { type Features, features } from "src/components/Table/features"; import { TableLayout } from "src/components/Table/TableLayout"; import { intl, T } from "src/locale"; import { MANAGE, STREAMS } from "src/modules/Permissions"; @@ -30,7 +25,7 @@ interface Props { onNew?: () => void; } export default function Table({ data, isFetching, isFiltered, onEdit, onDelete, onDisableToggle, onNew }: Props) { - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); const columns = useMemo( () => [ columnHelper.accessor((row: any) => row.owner, { @@ -47,7 +42,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete, columnHelper.accessor((row: any) => row, { id: "incomingPort", header: intl.formatMessage({ id: "column.incoming-port" }), - sortingFn: (a, b) => (a.original.incomingPort ?? 0) - (b.original.incomingPort ?? 0), + sortFn: (a, b) => (a.original.incomingPort ?? 0) - (b.original.incomingPort ?? 0), cell: (info: any) => { const value = info.getValue(); return ; @@ -56,7 +51,7 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete, columnHelper.accessor((row: any) => row, { id: "forwardHttpCode", header: intl.formatMessage({ id: "column.destination" }), - sortingFn: (a, b) => { + sortFn: (a, b) => { const aVal = `${a.original.forwardingHost}:${a.original.forwardingPort}`; const bVal = `${b.original.forwardingHost}:${b.original.forwardingPort}`; return aVal.localeCompare(bVal); @@ -174,14 +169,12 @@ export default function Table({ data, isFetching, isFiltered, onEdit, onDelete, const [sorting, setSorting] = useState([]); - const tableInstance = useReactTable({ + const tableInstance = useTable({ + features, columns, data, state: { sorting }, onSortingChange: setSorting, - getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), - rowCount: data.length, meta: { isFetching, }, diff --git a/frontend/src/pages/Users/Table.tsx b/frontend/src/pages/Users/Table.tsx index d07fc9bcff..a5a61057bd 100644 --- a/frontend/src/pages/Users/Table.tsx +++ b/frontend/src/pages/Users/Table.tsx @@ -7,7 +7,7 @@ import { IconShield, IconTrash, } from "@tabler/icons-react"; -import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; +import { createColumnHelper, useTable } from "@tanstack/react-table"; import { useMemo } from "react"; import type { User } from "src/api/backend"; import { @@ -18,6 +18,7 @@ import { TrueFalseFormatter, ValueWithDateFormatter, } from "src/components"; +import { type Features, features } from "src/components/Table/features"; import { TableLayout } from "src/components/Table/TableLayout"; import { intl, T } from "src/locale"; @@ -47,7 +48,7 @@ export default function Table({ onNewUser, onLoginAs, }: Props) { - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); const columns = useMemo( () => [ columnHelper.accessor((row: any) => row, { @@ -216,11 +217,10 @@ export default function Table({ ], ); - const tableInstance = useReactTable({ + const tableInstance = useTable({ + features, columns, data, - getCoreRowModel: getCoreRowModel(), - rowCount: data.length, meta: { isFetching, }, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index d5f803762f..eb0aa21f9f 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -3,170 +3,155 @@ "@adobe/css-tools@^4.4.0": - version "4.4.4" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.4.tgz#2856c55443d3d461693f32d2b96fb6ea92e1ffa9" - integrity sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg== + version "4.5.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.5.0.tgz#b5b71a25a4d16afa2482592ddfa62fccc60bc7d1" + integrity sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" - integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.29.0", "@babel/code-frame@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7" + integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw== dependencies: - "@babel/helper-validator-identifier" "^7.28.5" + "@babel/helper-validator-identifier" "^7.29.7" js-tokens "^4.0.0" picocolors "^1.1.1" -"@babel/generator@^7.29.0": - version "7.29.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" - integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== +"@babel/generator@^7.29.8": + version "7.29.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.8.tgz#4b0b887885422643339e09022148a4c4ebaa4979" + integrity sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg== dependencies: - "@babel/parser" "^7.29.0" - "@babel/types" "^7.29.0" + "@babel/parser" "^7.29.8" + "@babel/types" "^7.29.8" "@jridgewell/gen-mapping" "^0.3.12" "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" -"@babel/helper-globals@^7.28.0": - version "7.28.0" - resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" - integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== +"@babel/helper-globals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b" + integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA== "@babel/helper-module-imports@^7.16.7": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" - integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396" + integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g== dependencies: - "@babel/traverse" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" -"@babel/helper-string-parser@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" - integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== +"@babel/helper-string-parser@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f" + integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw== -"@babel/helper-validator-identifier@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" - integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== +"@babel/helper-validator-identifier@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2" + integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg== -"@babel/parser@^7.28.6", "@babel/parser@^7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" - integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== +"@babel/parser@^7.29.7", "@babel/parser@^7.29.8": + version "7.29.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.8.tgz#9653716a2f10c677b98fbc63d4bfb000c302cf17" + integrity sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA== dependencies: - "@babel/types" "^7.29.0" + "@babel/types" "^7.29.8" "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.24.7", "@babel/runtime@^7.26.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" - integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== - -"@babel/template@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" - integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== - dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/parser" "^7.28.6" - "@babel/types" "^7.28.6" - -"@babel/traverse@^7.28.6": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" - integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== - dependencies: - "@babel/code-frame" "^7.29.0" - "@babel/generator" "^7.29.0" - "@babel/helper-globals" "^7.28.0" - "@babel/parser" "^7.29.0" - "@babel/template" "^7.28.6" - "@babel/types" "^7.29.0" + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768" + integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw== + +"@babel/template@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700" + integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/types" "^7.29.7" + +"@babel/traverse@^7.29.7": + version "7.29.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.8.tgz#4111014cdc71a0f95d9471907590baa0b8a6b28a" + integrity sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/generator" "^7.29.8" + "@babel/helper-globals" "^7.29.7" + "@babel/parser" "^7.29.8" + "@babel/template" "^7.29.7" + "@babel/types" "^7.29.8" debug "^4.3.1" -"@babel/types@^7.28.6", "@babel/types@^7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" - integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== +"@babel/types@^7.29.7", "@babel/types@^7.29.8": + version "7.29.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.8.tgz#1229eef31d85156d70fa3f4cd859376d0eaf6863" + integrity sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg== dependencies: - "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.28.5" + "@babel/helper-string-parser" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" -"@biomejs/biome@^2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.4.15.tgz#cb84ad6eb4235e7230b3c105a825e9bc03399944" - integrity sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw== +"@biomejs/biome@^2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.5.10.tgz#c2a42fc6f9c7d9e12c1f77f63dfb6b5489c497b7" + integrity sha512-WRKXARA3kTuiV5sxqTpobJ/I0MVd4vk3pOL6wnp5az4LntFIhWTj1RWZq3DI9PCEN3lXcqy7p5aqUHzvq8AXyQ== optionalDependencies: - "@biomejs/cli-darwin-arm64" "2.4.15" - "@biomejs/cli-darwin-x64" "2.4.15" - "@biomejs/cli-linux-arm64" "2.4.15" - "@biomejs/cli-linux-arm64-musl" "2.4.15" - "@biomejs/cli-linux-x64" "2.4.15" - "@biomejs/cli-linux-x64-musl" "2.4.15" - "@biomejs/cli-win32-arm64" "2.4.15" - "@biomejs/cli-win32-x64" "2.4.15" - -"@biomejs/cli-darwin-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz#3469daa56ac3ff4f16588a120df706381a96f65c" - integrity sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg== - -"@biomejs/cli-darwin-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz#0697b81089409635da16682ac1e539165c262006" - integrity sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ== - -"@biomejs/cli-linux-arm64-musl@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz#c6af054e3732c361e9ad8c44070f909666b5616f" - integrity sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ== - -"@biomejs/cli-linux-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz#527cef60339649a442d51a9cd129ae9dfe9da926" - integrity sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug== - -"@biomejs/cli-linux-x64-musl@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz#b39292ad106c3d5a612bf3c61ba3119f66833013" - integrity sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w== - -"@biomejs/cli-linux-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz#7360b7f81ff03ec6d9350bedc76b89f783b0945d" - integrity sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g== - -"@biomejs/cli-win32-arm64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz#9542aac679174892a9379267e0c0048f8eee4d9f" - integrity sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w== - -"@biomejs/cli-win32-x64@2.4.15": - version "2.4.15" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz#80288e4eea8f916fc5c876e9a486baadb8de537d" - integrity sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ== - -"@emnapi/core@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.10.0.tgz#380ccc8f2412ea22d1d972df7f8ee23a3b9c7467" - integrity sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw== - dependencies: - "@emnapi/wasi-threads" "1.2.1" - tslib "^2.4.0" - -"@emnapi/runtime@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.10.0.tgz#4b260c0d3534204e98c6110b8db1a987d26ec87c" - integrity sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA== - dependencies: - tslib "^2.4.0" - -"@emnapi/wasi-threads@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz#28fed21a1ba1ce797c44a070abc94d42f3ae8548" - integrity sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w== - dependencies: - tslib "^2.4.0" + "@biomejs/cli-darwin-arm64" "2.5.10" + "@biomejs/cli-darwin-x64" "2.5.10" + "@biomejs/cli-linux-arm64" "2.5.10" + "@biomejs/cli-linux-arm64-musl" "2.5.10" + "@biomejs/cli-linux-x64" "2.5.10" + "@biomejs/cli-linux-x64-musl" "2.5.10" + "@biomejs/cli-win32-arm64" "2.5.10" + "@biomejs/cli-win32-x64" "2.5.10" + +"@biomejs/cli-darwin-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.10.tgz#f1453a7f2e63f228a34645df1c33962f22a6c2a8" + integrity sha512-ItCrxKK6SXVT6flYs0qIuBd4AA3TTTl4d66Re6YI2FuGZnN85NmuYNzkiTJUyYw8qBLv69L5zTUB6uyWd++h3Q== + +"@biomejs/cli-darwin-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.10.tgz#e21041e7bfab01cd453f609b940bf613713d0e24" + integrity sha512-yLsPU9pAmtChXDu8vhKAzErqe+LeeYuwuUB2FZMkRitsmdodxsYRa9KHrFispsUHzzOu+9HB3nP/TQxyia+Sjw== + +"@biomejs/cli-linux-arm64-musl@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.10.tgz#57fc8aee25c08ca6c14526ccc44e282e7ba96eb6" + integrity sha512-t1QAKZwQJRB4dvgJSgFiQ4BNfNPChg69BNonz854qLVxnjT3UvDzQg9mbkTJRu35ZqU0Rw10A73J8Urgbg2RPw== + +"@biomejs/cli-linux-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.10.tgz#aef789a71e5aa86f5a0e1aff6cb4c1b757ec5be1" + integrity sha512-VG8uQW/86a1roLaIFvtIbEigxIdzdJ190oGyg1tV7VYeQtOS+x10sflk7WbuXgw91EtZX5DlIIIej1YqkNLlcg== + +"@biomejs/cli-linux-x64-musl@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.10.tgz#1aebe9f928dc72dc3c112e60f1211a4d646990c4" + integrity sha512-pgDDqp9JybHm2I0KRgzN6i4+lt8xu4iqxUwLzglUMmOmyRTU1AYBGKzh9sNMOtIjah7xoWvKHlLVetvyifzoiQ== + +"@biomejs/cli-linux-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.10.tgz#a82b414abf5d9668fb035ee50a710bf78a7c5fbf" + integrity sha512-4O6T0eq2heoHZN0a9UX+rWQoxXEBaKf+lRi2hbsGlHneUz9BWXM76nEWMK7Eeq8gzMxR1khQB6BFpAASpeXqGg== + +"@biomejs/cli-win32-arm64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.10.tgz#db671cf67d7040a374e8cdda5aebe73c3f4ffba0" + integrity sha512-pxAbxduPO4xq/Cvgaa2lOrs9BB0hEXmmDqfMNP4ZOffGOkUrD1/QGw9UAMpFQpX2P8MqTIIRuQKcmetum4Oa6A== + +"@biomejs/cli-win32-x64@2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.10.tgz#3bdeaf5856f21aec6b6c50a7bca5464b9cda5623" + integrity sha512-M+2dgBsl3lXRiTfgPVc2p3anS4Tocojke4rzFLScZ2Y/wmF+36dRb1iHCLiyGqOzQGyTplZH1HnEYviiAqi3nA== + +"@corvu/utils@~0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@corvu/utils/-/utils-0.4.2.tgz#ae867221297fd1e362efe41f081c42d7c746ff61" + integrity sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA== + dependencies: + "@floating-ui/dom" "^1.6.11" "@emotion/babel-plugin@^11.13.5": version "11.13.5" @@ -256,81 +241,121 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== -"@floating-ui/core@^1.7.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.4.tgz#4a006a6e01565c0f87ba222c317b056a2cffd2f4" - integrity sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg== +"@floating-ui/core@^1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.8.0.tgz#d01c0bbea02e4a57f6fd7d5de6fc2c5c7dca40e1" + integrity sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ== + dependencies: + "@floating-ui/utils" "^0.2.12" + +"@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.5.1", "@floating-ui/dom@^1.6.11": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.8.0.tgz#8a20e6facbe2456afdbeb6c8b968a72df689cf63" + integrity sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg== + dependencies: + "@floating-ui/core" "^1.8.0" + "@floating-ui/utils" "^0.2.12" + +"@floating-ui/utils@^0.2.12": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.12.tgz#afefe785949f16ac4cdd1e695935a321572dd56a" + integrity sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww== + +"@formatjs/cli-native-darwin-arm64@1.1.24": + version "1.1.24" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-darwin-arm64/-/cli-native-darwin-arm64-1.1.24.tgz#fd3eacb6653b0fdd81f123defbb6752072478a97" + integrity sha512-2i/fKUcawvTe022vN1LcpCJMBHcN2pFgOzg3Hr24jV0QMpoZVpB5RuM8fhZCy9E/STnOTP+P5W9uuPhg5eCGUA== + +"@formatjs/cli-native-linux-arm64-musl@1.0.22": + version "1.0.22" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-arm64-musl/-/cli-native-linux-arm64-musl-1.0.22.tgz#bd9939c40cfc45d3e2ed73200906dd9aa1aa43aa" + integrity sha512-YUJ1ArreQGEdr2VaBIvpUVx3242YRFAwaKljlm0bOAckdk1JogzGnxIb5OJzFxlKiZkXWGFlO+erpRB6q0+kHg== + +"@formatjs/cli-native-linux-arm64@1.2.24": + version "1.2.24" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-arm64/-/cli-native-linux-arm64-1.2.24.tgz#8ff72faeaa658f69a2f2dc1491decc243ff08411" + integrity sha512-L0hFov7dgC6m9WM2cqolaL3zA48vpwe/gqd7MKILt+TrHR4ZlVv9CXvzXMDucn//FcTZw0NFBKgVXcHvlimY2g== + +"@formatjs/cli-native-linux-x64-musl@1.0.22": + version "1.0.22" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-x64-musl/-/cli-native-linux-x64-musl-1.0.22.tgz#5b137b928aff22b496ff5aea6a8f974d4188f149" + integrity sha512-hUwkDw47LQ0ESJvKsbZOWI50w/NP1hATfRrUy9mGRCRqKj1YTJ/HQxOjVfnrpiVEImjs4Ptws69RuIgxB5QGOA== + +"@formatjs/cli-native-linux-x64@1.1.24": + version "1.1.24" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-x64/-/cli-native-linux-x64-1.1.24.tgz#23a421980b85a60266dbccd1d236d575ebdda54e" + integrity sha512-bp6FKYz8AQaHdeNI6rvMSk49ni4/uS+6AoxL/GiKXv2fL8zc459mkctTnwGR9Ol2in71Gq+nFKoZGFS50EHWCA== + +"@formatjs/cli-native-win32-x64@1.1.25": + version "1.1.25" + resolved "https://registry.yarnpkg.com/@formatjs/cli-native-win32-x64/-/cli-native-win32-x64-1.1.25.tgz#509060f7e0cc227a52e4677f6421da6fad48b224" + integrity sha512-tYjaYxtfBoGClwnBMtGuMQV/hbXY3mrGR5QRo9Tzk9Uwpa573gojtI8sqhn5jkzqjKPG1Ob3vVIJxcJmSnqemg== + +"@formatjs/cli@^6.16.30": + version "6.16.30" + resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-6.16.30.tgz#436549695e81af050747abcfac3af366c96546fa" + integrity sha512-9pHgUriIJAsHfkoYuShydq5jHMp0IMQk7sdIkXgqD3m5UKTZIDfOyuJyuqJM5T55HOxz97y4iSSoWp7rfgdvNA== + optionalDependencies: + "@formatjs/cli-native-darwin-arm64" "1.1.24" + "@formatjs/cli-native-linux-arm64" "1.2.24" + "@formatjs/cli-native-linux-arm64-musl" "1.0.22" + "@formatjs/cli-native-linux-x64" "1.1.24" + "@formatjs/cli-native-linux-x64-musl" "1.0.22" + "@formatjs/cli-native-win32-x64" "1.1.25" + +"@formatjs/fast-memoize@3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-3.1.7.tgz#5f79b3756e4bcb5faee47b3a2f01216e1212c9e4" + integrity sha512-zXfhLpvA6T7+efdt9JLbBwZ00tT7NsBMDVnDu8rpHeNNv8KfRZAMo2gkG0k9lK/Nzc//3kJ9pImsfuJxk3KhUA== + +"@formatjs/icu-messageformat-parser@3.5.17": + version "3.5.17" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.17.tgz#7ac90ff6dde99468cd0b4a3f55344ccf8ae2ed87" + integrity sha512-cN9jhVqT7u0K9tix43fhjoUwL0nazyW6zsNIXs2QdPADr+nurPfYyssUiMqcSCGlPcCiqnYVxgSn7zBSuI+5Bg== + dependencies: + "@formatjs/icu-skeleton-parser" "2.1.11" + +"@formatjs/icu-skeleton-parser@2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.11.tgz#09226edf55a18e3fea80304d2cc95aaeb0095436" + integrity sha512-j8cUmOJzVgkHuS0QiQ6ga76UIoLOFSAMWhs7aZJztH3aAdCOAE6vpC8KVvFB4cU10ON0y2/5oOVmPJ43s2lTwA== + +"@formatjs/intl@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-4.2.0.tgz#fadf90f2b1d02faaa68fa770f66a1f384e82653b" + integrity sha512-FbiaRjnQjjqo8FzayDEuuFLj+lCrSEDEmeXXGRpBUioaukr/+4djq4TYIpXnsVh2DWqYyOrMu8cLpc/rGmVHlw== dependencies: - "@floating-ui/utils" "^0.2.10" + "@formatjs/fast-memoize" "3.1.7" + "@formatjs/icu-messageformat-parser" "3.5.17" + intl-messageformat "11.2.14" -"@floating-ui/dom@^1.0.1": - version "1.7.5" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.5.tgz#60bfc83a4d1275b2a90db76bf42ca2a5f2c231c2" - integrity sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg== +"@internationalized/date@^3.12.3": + version "3.12.3" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.12.3.tgz#e11d14dbf12bf45057dd5996bac77f7c2f89ff9c" + integrity sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q== dependencies: - "@floating-ui/core" "^1.7.4" - "@floating-ui/utils" "^0.2.10" - -"@floating-ui/utils@^0.2.10": - version "0.2.10" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" - integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== - -"@formatjs/cli-native-darwin-arm64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@formatjs/cli-native-darwin-arm64/-/cli-native-darwin-arm64-1.1.0.tgz#c47df2ec7c1d27643900af77c474bd224b4587dc" - integrity sha512-ygEpFpmRjbAKanWaeto/eUItyuK18667mdDzpDg3CTzc15WYzjZKnwJNFUuPFvFA4hiod1tnhXT1eiXmc1wWNg== - -"@formatjs/cli-native-linux-arm64@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-arm64/-/cli-native-linux-arm64-1.2.0.tgz#3ddcafb006351417e82785b809a1ab1fbbb2c577" - integrity sha512-G6YuIVD8D6hZjnsD/aYZQ2qMHSve7IadEiXgKiDfFQBbyrkjDAlt6LDSqq4qnuv3WJ7/jAOn/An6n/bGyt0rLg== - -"@formatjs/cli-native-linux-x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@formatjs/cli-native-linux-x64/-/cli-native-linux-x64-1.1.0.tgz#1a3f01ea47f971a0dd0d7f49b98df237375862fa" - integrity sha512-AxORf5LR14HvXU4ov9gnhLrNIS2DYKqKMkRkprUhuh+ljba1riF05msK8KzslEPYQoeYKc5A0OZp57poh4xz/g== - -"@formatjs/cli-native-win32-x64@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@formatjs/cli-native-win32-x64/-/cli-native-win32-x64-1.1.1.tgz#a911b22c8f5ccfe4aff5a00276ee4274f4b81079" - integrity sha512-2vYgm7dzAb7wA9KjOOJGxZiSShwBNK4dEmgiJ1lRpEIz6RKMZ6wBY4UVn03VdAv8djJ7r6RK4Xyd2ouGcbh9Bg== - -"@formatjs/cli@^6.16.3": - version "6.16.3" - resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-6.16.3.tgz#728a17c1deaf1fec0ace554b2c72695f18253231" - integrity sha512-AN6uZR1xnl3V215HHJiKiA+DvNMrO/XfQ7hOyq3gXfHJwKSgLLQFtSFxw9A1O0SaGC2E2Kwo4mqwS1ZCLGe/qw== - optionalDependencies: - "@formatjs/cli-native-darwin-arm64" "1.1.0" - "@formatjs/cli-native-linux-arm64" "1.2.0" - "@formatjs/cli-native-linux-x64" "1.1.0" - "@formatjs/cli-native-win32-x64" "1.1.1" - -"@formatjs/fast-memoize@3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-3.1.5.tgz#bdfe0b884cdecc25100534086f36a0b30bd15b3b" - integrity sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A== + "@swc/helpers" "^0.5.0" -"@formatjs/icu-messageformat-parser@3.5.10": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.10.tgz#0ced2d6e8009eed57c6f0e7b4cc51dfea63b9bff" - integrity sha512-XeJihYLy1lCe19xfK1KWKG/betBOK2rB0luL8lSkjfvJj0zP+LTJvkC+RKd0jsFI8mWxN71LrarHSrEXE8xxOQ== +"@internationalized/number@^3.2.1": + version "3.6.8" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.8.tgz#aaa3e16fb9d64a8d7f130ccf848c626914dfdf9e" + integrity sha512-8UmMFia46DUt+k97zKd9fKWXcWHR+k8ae3eYzILETuT2KbIvLyOfac7zesw+sJdRAAZ7Q9pM1Mk22aXp2LD0Ig== dependencies: - "@formatjs/icu-skeleton-parser" "2.1.9" + "@swc/helpers" "^0.5.0" -"@formatjs/icu-skeleton-parser@2.1.9": - version "2.1.9" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.9.tgz#746edae664b2ef148df1301845d1bb40000bbebb" - integrity sha512-rsxswgHMfU1zUgB2byc08fesf83wLGjFnzLCEtuf00mx2doiqc6pYrf67raI37XqdRcGUviQepk2UKGqpng74Q== +"@internationalized/number@^3.6.7": + version "3.6.7" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.7.tgz#5a0a8fa413b5f8679a59dcf37e2a74dc508b8371" + integrity sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg== + dependencies: + "@swc/helpers" "^0.5.0" -"@formatjs/intl@4.1.12": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-4.1.12.tgz#a29521f9bba79df1690c430f3d2cee8817778674" - integrity sha512-r288ut+p+CUQZSg+0gAT+D0i6xgrnoxE0B4HTbPY2zei/AtYmFhlu87BKjgCf1CweH4pZIbr152JFjxO8jVb1A== +"@internationalized/string@^3.2.10": + version "3.2.10" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.10.tgz#c38bd59a69509a41bf7422f1b2fc3af7468e4322" + integrity sha512-PDx6//vHSpRnHfxqMqto11zQvhsaU74O3mKv2F/0eicGZcl9NLjQmGlbHz/LsJh5tLKp4A4L7ZVTzN1/MmMTvA== dependencies: - "@formatjs/fast-memoize" "3.1.5" - "@formatjs/icu-messageformat-parser" "3.5.10" - intl-messageformat "11.2.7" + "@swc/helpers" "^0.5.0" "@jridgewell/gen-mapping@^0.3.12": version "0.3.13" @@ -365,106 +390,119 @@ dependencies: jsbi "^4.3.0" -"@napi-rs/wasm-runtime@^1.1.4": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz#a46bbfedc29751b7170c5d23bc1d8ee8c7e3c1e1" - integrity sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow== - dependencies: - "@tybys/wasm-util" "^0.10.1" - -"@oxc-project/types@=0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.132.0.tgz#d77243df4fe1a0a1e60e12ac6240fa898d2363ff" - integrity sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ== - -"@parcel/watcher-android-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz#5f32e0dba356f4ac9a11068d2a5c134ca3ba6564" - integrity sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A== - -"@parcel/watcher-darwin-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz#88d3e720b59b1eceffce98dac46d7c40e8be5e8e" - integrity sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA== - -"@parcel/watcher-darwin-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz#bf05d76a78bc15974f15ec3671848698b0838063" - integrity sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg== - -"@parcel/watcher-freebsd-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz#8bc26e9848e7303ac82922a5ae1b1ef1bdb48a53" - integrity sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng== - -"@parcel/watcher-linux-arm-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz#1328fee1deb0c2d7865079ef53a2ba4cc2f8b40a" - integrity sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ== - -"@parcel/watcher-linux-arm-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz#bad0f45cb3e2157746db8b9d22db6a125711f152" - integrity sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg== - -"@parcel/watcher-linux-arm64-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz#b75913fbd501d9523c5f35d420957bf7d0204809" - integrity sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA== - -"@parcel/watcher-linux-arm64-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz#da5621a6a576070c8c0de60dea8b46dc9c3827d4" - integrity sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA== - -"@parcel/watcher-linux-x64-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz#ce437accdc4b30f93a090b4a221fd95cd9b89639" - integrity sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ== - -"@parcel/watcher-linux-x64-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz#02400c54b4a67efcc7e2327b249711920ac969e2" - integrity sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg== - -"@parcel/watcher-win32-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz#caae3d3c7583ca0a7171e6bd142c34d20ea1691e" - integrity sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q== - -"@parcel/watcher-win32-ia32@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz#9ac922550896dfe47bfc5ae3be4f1bcaf8155d6d" - integrity sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g== - -"@parcel/watcher-win32-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz#73fdafba2e21c448f0e456bbe13178d8fe11739d" - integrity sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw== +"@kobalte/core@^0.13.4": + version "0.13.14" + resolved "https://registry.yarnpkg.com/@kobalte/core/-/core-0.13.14.tgz#6d46ada9a427e07f73fb61123a03220277a793d7" + integrity sha512-SBVB1lnvYbYt2x3t7fG0lo5fGLEbHQ6PII3NDPva8vD5e2v53On84ZVQiuIk0XI/55R4GQhden7Yem+R/XR8uQ== + dependencies: + "@floating-ui/dom" "^1.5.1" + "@internationalized/number" "^3.2.1" + "@kobalte/utils" "^0.9.2" + "@solid-primitives/props" "^3.1.8" + "@solid-primitives/resize-observer" "^2.0.26" + solid-presence "^0.2.0" + solid-prevent-scroll "^0.1.11" + +"@kobalte/utils@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@kobalte/utils/-/utils-0.9.2.tgz#cb4ccbbd93efda1f2e3602ffeec7fd8b58b69e7b" + integrity sha512-jRVXr+zsVHxzDXRoh+CDeXzvCsFJ6uiHhqqNQ26Cw9ZsZ3D6nqPUBt1gGVtj2ZPmRL3a9Uk1v8D1aJ8/I12Dow== + dependencies: + "@solid-primitives/event-listener" "^2.2.14" + "@solid-primitives/keyed" "^1.2.0" + "@solid-primitives/map" "^0.4.7" + "@solid-primitives/media" "^2.2.4" + "@solid-primitives/props" "^3.1.8" + "@solid-primitives/refs" "^1.0.5" + "@solid-primitives/utils" "^6.2.1" + +"@oxc-project/types@=0.150.0": + version "0.150.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.150.0.tgz#e9be0840114655016b16f1c05ddaaa01df5b8853" + integrity sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw== + +"@parcel/watcher-android-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz#99aaa3223d43807c9340af439cad7e9b6d26ada6" + integrity sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA== + +"@parcel/watcher-darwin-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz#024496e586b4744f09ce532bbe89fe38ef02a64e" + integrity sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw== + +"@parcel/watcher-darwin-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz#a4621df1359a93d39a332d9bab5ff09016a0608f" + integrity sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw== + +"@parcel/watcher-freebsd-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz#7f565ed1a5b3a5e604e6a4799121518265d62a3d" + integrity sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ== + +"@parcel/watcher-linux-arm-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz#ad7d3825e67b81999165da42593022045abc0889" + integrity sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg== + +"@parcel/watcher-linux-arm-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz#fe7d1cccb2c483215c090e938cf5cf404d2f9a8c" + integrity sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw== + +"@parcel/watcher-linux-arm64-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz#7e239dcb4646c4c79f006a7131a48238249530da" + integrity sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g== + +"@parcel/watcher-linux-arm64-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz#c58b8d9c6d8d81594be00dd83aab741c1aaf7e0e" + integrity sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA== + +"@parcel/watcher-linux-x64-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz#5184fa9a770478d86e56875f4ee163a0abdc8791" + integrity sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A== + +"@parcel/watcher-linux-x64-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz#2d1c55aa7246cbc7670e2612058a8a542c9cf246" + integrity sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw== + +"@parcel/watcher-win32-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz#15e09432040fee9e2213aa9c10ed589012526def" + integrity sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ== + +"@parcel/watcher-win32-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz#9bee199a2a4accd557b451ac2c1c793f305ae012" + integrity sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A== "@parcel/watcher@^2.4.1": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.6.tgz#3f932828c894f06d0ad9cfefade1756ecc6ef1f1" - integrity sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ== + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.6.0.tgz#99661f6220070b76a766aba6b7e313a087a1be4f" + integrity sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w== dependencies: detect-libc "^2.0.3" is-glob "^4.0.3" node-addon-api "^7.0.0" - picomatch "^4.0.3" + picomatch "^4.0.4" optionalDependencies: - "@parcel/watcher-android-arm64" "2.5.6" - "@parcel/watcher-darwin-arm64" "2.5.6" - "@parcel/watcher-darwin-x64" "2.5.6" - "@parcel/watcher-freebsd-x64" "2.5.6" - "@parcel/watcher-linux-arm-glibc" "2.5.6" - "@parcel/watcher-linux-arm-musl" "2.5.6" - "@parcel/watcher-linux-arm64-glibc" "2.5.6" - "@parcel/watcher-linux-arm64-musl" "2.5.6" - "@parcel/watcher-linux-x64-glibc" "2.5.6" - "@parcel/watcher-linux-x64-musl" "2.5.6" - "@parcel/watcher-win32-arm64" "2.5.6" - "@parcel/watcher-win32-ia32" "2.5.6" - "@parcel/watcher-win32-x64" "2.5.6" + "@parcel/watcher-android-arm64" "2.6.0" + "@parcel/watcher-darwin-arm64" "2.6.0" + "@parcel/watcher-darwin-x64" "2.6.0" + "@parcel/watcher-freebsd-x64" "2.6.0" + "@parcel/watcher-linux-arm-glibc" "2.6.0" + "@parcel/watcher-linux-arm-musl" "2.6.0" + "@parcel/watcher-linux-arm64-glibc" "2.6.0" + "@parcel/watcher-linux-arm64-musl" "2.6.0" + "@parcel/watcher-linux-x64-glibc" "2.6.0" + "@parcel/watcher-linux-x64-musl" "2.6.0" + "@parcel/watcher-win32-arm64" "2.6.0" + "@parcel/watcher-win32-x64" "2.6.0" "@popperjs/core@^2.11.8": version "2.11.8" @@ -472,11 +510,17 @@ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@react-aria/ssr@^3.5.0": - version "3.9.10" - resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.10.tgz#7fdc09e811944ce0df1d7e713de1449abd7435e6" - integrity sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ== + version "3.10.1" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.10.1.tgz#d082600c811e35e8ab780c55c47b5d731359aaf7" + integrity sha512-jn038/ZYmu6DpfXJ6r2U9zFFppjbc9wnApPJSCxao2RZVEqep4YyoniHSy8qv6V21/xyS4IV7W9a+X2jOjSuag== dependencies: "@swc/helpers" "^0.5.0" + react-aria "^3.48.0" + +"@react-types/shared@^3.36.1": + version "3.36.1" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.36.1.tgz#edb8081e3872ae68a4eb4a65e62233d0754ec186" + integrity sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag== "@restart/hooks@^0.4.9": version "0.4.16" @@ -507,162 +551,288 @@ uncontrollable "^8.0.4" warning "^4.0.3" -"@rolldown/binding-android-arm64@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz#ebe1264e43ba5bb224c58c85e0ac238f87e5ad14" - integrity sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ== - -"@rolldown/binding-darwin-arm64@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz#f972fb71bc03840629bee923babbb7048d14a5d0" - integrity sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w== - -"@rolldown/binding-darwin-x64@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz#da1c062c135e1e50067084be5ab8055cc1e05b29" - integrity sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA== - -"@rolldown/binding-freebsd-x64@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz#a4c8532072705ce597c0d75418513709b75b3f1d" - integrity sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA== - -"@rolldown/binding-linux-arm-gnueabihf@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz#78f3bd274a1bab07356017d728b70289f04011c1" - integrity sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w== - -"@rolldown/binding-linux-arm64-gnu@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz#4dc530aed0b554762ffc1a5e4f016b8be495eea0" - integrity sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig== - -"@rolldown/binding-linux-arm64-musl@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz#56043cdf4768ea3184bb08a3f45b24f183003877" - integrity sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw== - -"@rolldown/binding-linux-ppc64-gnu@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz#92eba998d5cd9e4cfc8b95407b4b80f46dacadf4" - integrity sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA== - -"@rolldown/binding-linux-s390x-gnu@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz#50b0e95dc3c22af1ecd1669ad7e6030e6860819e" - integrity sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ== - -"@rolldown/binding-linux-x64-gnu@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz#d9fd5af004a373a2d26a09ce8fb66bd0927cbc0b" - integrity sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ== - -"@rolldown/binding-linux-x64-musl@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz#c0ad80adf4d4df430d0ec309e97924db85065c3c" - integrity sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw== - -"@rolldown/binding-openharmony-arm64@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz#341fc254ef7759f865bb219beb5cea6f5c9a44f6" - integrity sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w== - -"@rolldown/binding-wasm32-wasi@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz#65f9389f74168fd54e67b12d0630fb90348051f0" - integrity sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ== - dependencies: - "@emnapi/core" "1.10.0" - "@emnapi/runtime" "1.10.0" - "@napi-rs/wasm-runtime" "^1.1.4" - -"@rolldown/binding-win32-arm64-msvc@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz#17e80f3402308f12c76ff4172768d51715b522ac" - integrity sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A== - -"@rolldown/binding-win32-x64-msvc@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz#875cfa37f26d11692dbe28b8331499c97aa99d1f" - integrity sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ== - -"@rolldown/pluginutils@^1.0.0": +"@rolldown/binding-android-arm-eabi@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz#b38df5a6997454696207ac16b322a3ac1ff79e16" + integrity sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw== + +"@rolldown/binding-android-arm64@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz#bc2bf135c1e787f94b29bc321c1db0bd2884b5a7" + integrity sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg== + +"@rolldown/binding-darwin-arm64@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz#052049707ccc4cfe0b035aa8c37c4e55523eecbb" + integrity sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw== + +"@rolldown/binding-darwin-x64@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz#ea67496811e4e1c2f76d5647f248073e204f5462" + integrity sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw== + +"@rolldown/binding-freebsd-x64@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz#4b4a605f8c24a7235afb5da9b4b8bc8974446bb5" + integrity sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g== + +"@rolldown/binding-linux-arm-gnueabihf@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz#a36c6961fb24b86176463559dcd0edbe48ea74f1" + integrity sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw== + +"@rolldown/binding-linux-arm64-gnu@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz#7b43488618dd6f9d392e9adaaffd4d7f4bb785ce" + integrity sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw== + +"@rolldown/binding-linux-arm64-musl@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz#8168a2e2ce7d9e28847f3019c98abf76c0ec5fe2" + integrity sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA== + +"@rolldown/binding-linux-ppc64-gnu@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz#8f52aac40788feac33056f111176a7bf8fbc297a" + integrity sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw== + +"@rolldown/binding-linux-s390x-gnu@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz#80cdfa507fd87bc37c47c5a16ca578f619ee3a69" + integrity sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ== + +"@rolldown/binding-linux-x64-gnu@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz#c2f89cdf3b223b2ba3cd4c0fdc760b360c02edf5" + integrity sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q== + +"@rolldown/binding-linux-x64-musl@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz#3fbb6bce4c8a8260cb63fc2dba182c8649930c6c" + integrity sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ== + +"@rolldown/binding-openharmony-arm64@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz#c8cd18d7fd14222e2068cd0640bba88d2cd710f8" + integrity sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg== + +"@rolldown/binding-win32-arm64-msvc@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz#cff9ed3be36979d7d77306bf9dca1a27ed17c1f0" + integrity sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww== + +"@rolldown/binding-win32-x64-msvc@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz#6e6a3a7ac86eb46bed61e685a9e7cccfacc21b7a" + integrity sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g== + +"@rolldown/pluginutils@^1.0.0", "@rolldown/pluginutils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz#e3fcee093fbb5ce765e1ad088ff4de2889f6f9be" integrity sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw== +"@solid-primitives/event-listener@^2.2.14", "@solid-primitives/event-listener@^2.4.6": + version "2.4.6" + resolved "https://registry.yarnpkg.com/@solid-primitives/event-listener/-/event-listener-2.4.6.tgz#95704ae633b92551334e48399ad8785aa7f9f426" + integrity sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/keyed@^1.2.0", "@solid-primitives/keyed@^1.2.2": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@solid-primitives/keyed/-/keyed-1.5.3.tgz#df60e7a079cc99ef80d22e4c03bb80eabc106392" + integrity sha512-zNadtyYBhJSOjXtogkGHmRxjGdz9KHc8sGGVAGlUABkE8BED2tbIZoxkwSqzOwde8OcUEH0bb5DLZUWIMvyBSA== + +"@solid-primitives/map@^0.4.7": + version "0.4.13" + resolved "https://registry.yarnpkg.com/@solid-primitives/map/-/map-0.4.13.tgz#f0096c53ad3405fde444a738f4b1adb0f402ea16" + integrity sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew== + dependencies: + "@solid-primitives/trigger" "^1.1.0" + +"@solid-primitives/media@^2.2.4": + version "2.3.6" + resolved "https://registry.yarnpkg.com/@solid-primitives/media/-/media-2.3.6.tgz#9c4c64410ab8a066871d6a45ad69529289f57b3e" + integrity sha512-pk49gPOq/UMRUJ+pTSrOfBiR8xJjRYHXIf1iR/jSnyQ/KroU+ZXhkZzavC7hvfp2vJeOTW5k2/HN0r3Q1VJ7Pw== + dependencies: + "@solid-primitives/event-listener" "^2.4.6" + "@solid-primitives/rootless" "^1.5.4" + "@solid-primitives/static-store" "^0.1.4" + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/props@^3.1.8": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@solid-primitives/props/-/props-3.2.4.tgz#517b387fde97e85d701f8d72866f5480a23ec4cc" + integrity sha512-MXXdvi2TSB6d+0N6ueA/HP1j/Kh9SEc4WdF1ZDMLwPagxW6pIHHSS9xbRO0RjqSVpNP4j0nxCWT1hx3CkJNhNA== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/refs@^1.0.5": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@solid-primitives/refs/-/refs-1.1.4.tgz#d8aef55a51d5141527b6ad151f7c98a207d3b644" + integrity sha512-bLjwIs6ZPu8NQnuw04sU3Zc8qKSpbc0umUU/O4SHf6oWOdO4+dHY8vb1T7C4b/Tg103+9WGr6sEE0+NFlbaB/A== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/resize-observer@^2.0.26": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@solid-primitives/resize-observer/-/resize-observer-2.2.0.tgz#f6d76c0f765bb2008117c2e7504eb1707ef1268c" + integrity sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww== + dependencies: + "@solid-primitives/event-listener" "^2.4.6" + "@solid-primitives/rootless" "^1.5.4" + "@solid-primitives/static-store" "^0.1.4" + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/rootless@^1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@solid-primitives/rootless/-/rootless-1.5.4.tgz#10ee4112bcadf51a57c67f0bf728e1651a077233" + integrity sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/static-store@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@solid-primitives/static-store/-/static-store-0.1.4.tgz#fe6792b4268dd9b06374b28b1d9fc6dfb8da364d" + integrity sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/storage@^1.3.11": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@solid-primitives/storage/-/storage-1.3.11.tgz#2d273f3ab9e76e8819459fd9f0fccce8b09ebedb" + integrity sha512-PpQWR3TaTxHIJFbI9ZssYTM4Aa67g1vJIgps4TPhcXzHqqomrPAIveFC2FG7SDQoi9YQia8FVBjigELziJpfIg== + dependencies: + "@solid-primitives/utils" "^6.2.0" + +"@solid-primitives/transition-group@^1.0.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solid-primitives/transition-group/-/transition-group-1.1.2.tgz#be9af05871a7ca6323277f9782f4aeb20cb7f73f" + integrity sha512-gnHS0OmcdjeoHN9n7Khu8KNrOlRc8a2weETDt2YT6o1zeW/XtUC6Db3Q9pkMU/9cCKdEmN4b0a/41MKAHRhzWA== + +"@solid-primitives/trigger@^1.1.0": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@solid-primitives/trigger/-/trigger-1.2.4.tgz#5811053de6c650eb1aed504f77086433beefe208" + integrity sha512-Ju0e+ZOD7hpOp7nptJimvDSZHWFvIvF9iBWMvuwt30smX7c5wmB8Kmc0AdDuv0wOTi06PQ1J5IrP1WJbH2yUBQ== + dependencies: + "@solid-primitives/utils" "^6.4.1" + +"@solid-primitives/utils@^6.2.0", "@solid-primitives/utils@^6.2.1", "@solid-primitives/utils@^6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@solid-primitives/utils/-/utils-6.4.1.tgz#aaa9006ac9dfa7b99b1060ab78669a8723ab2962" + integrity sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg== + "@standard-schema/spec@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== "@swc/helpers@^0.5.0": - version "0.5.18" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.18.tgz#feeeabea0d10106ee25aaf900165df911ab6d3b1" - integrity sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ== + version "0.5.23" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.23.tgz#19287d0d86d962b111376039a50c792902c9a86a" + integrity sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw== dependencies: tslib "^2.8.0" -"@tabler/core@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@tabler/core/-/core-1.4.0.tgz#9e011289d92cf6120655793cef6576fd67eb07f3" - integrity sha512-5BigzOlbOH9N0Is4u0rYNRCiwtnUXWO57K9zwuscygcicAa8UV9MGaS4zTgQsZEtZ9tsNANhN/YD8gCBGKYCiw== +"@tabler/core@^1.5.1": + version "1.5.1" + resolved "https://registry.yarnpkg.com/@tabler/core/-/core-1.5.1.tgz#d083f17521acb7df4bc231bc79e653bfeae268c9" + integrity sha512-PI9rJq4H4lBh53YP/J+m5Uz6lqVQbsGPmWCMN34IP4KQQ/wy28YMO6a3Eiz1cQHdFFr+3MlU3yYhXdzvFGJfqw== dependencies: "@popperjs/core" "^2.11.8" - bootstrap "5.3.7" - -"@tabler/icons-react@^3.44.0": - version "3.44.0" - resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.44.0.tgz#26e84ee0ef756bfae5dcbd8265312ba3cd5a91d9" - integrity sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg== - dependencies: - "@tabler/icons" "3.44.0" - -"@tabler/icons@3.44.0": - version "3.44.0" - resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.44.0.tgz#286b203aac98591e27360de03974762568bbb272" - integrity sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA== -"@tanstack/query-core@5.100.14": - version "5.100.14" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.100.14.tgz#6bf11c9a6a33dbbbba21f05d880b93930d80000c" - integrity sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew== +"@tabler/icons-react@^3.46.0": + version "3.46.0" + resolved "https://registry.yarnpkg.com/@tabler/icons-react/-/icons-react-3.46.0.tgz#9840606d10aab071ad2c0dbdfcfba0eef6e9825d" + integrity sha512-CCm7xJWhDT2PH4ZIFkP6AgYKtVhq0gpYkjUN+GVh1AzmIQaa77OW0bQPBPQiTE0PsXMR9oSxFqA3qBglzPyrVQ== + dependencies: + "@tabler/icons" "3.46.0" + +"@tabler/icons@3.46.0": + version "3.46.0" + resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.46.0.tgz#28ba3f4895715863fdd78b49a5617764c9557fe5" + integrity sha512-f2RYFl3fzPwj5WO82x6en0dmkjefxEfOm16D1ByM6cj/McNiwOkL4VaPUoP9VVIrXAD9WnTSVFr70px703b//A== + +"@tanstack/match-sorter-utils@^8.19.4": + version "8.19.4" + resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz#dacf772b5d94f4684f10dbeb2518cf72dccab8a5" + integrity sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg== + dependencies: + remove-accents "0.5.0" + +"@tanstack/query-core@5.102.8": + version "5.102.8" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.102.8.tgz#c55c31b4f99124054805ce8ec8137c84108f3252" + integrity sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg== + +"@tanstack/query-core@5.103.1": + version "5.103.1" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.103.1.tgz#57c1db20679b98e793a1fe8e4a55a0619d2d681f" + integrity sha512-rms8HqTGp6zA00dM+cUQ2eBcgzNJefuu5CAMB37i/6MiGT1zulPOytCFu2a0qjLqVR2n1jENPj9woqFQNuCzWA== + +"@tanstack/query-devtools@5.103.1": + version "5.103.1" + resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.103.1.tgz#4691fc78c33e98304e6b3597d8ac67f3cd2b5ef8" + integrity sha512-xMOcnULRPEjww0A/0RnweNmcZ5hesLjTekqf8SHxf+BJH729qz6sUu5TsOWFo7J4fu3OR50MeuJUsM3BN78Kfw== + dependencies: + "@kobalte/core" "^0.13.4" + "@solid-primitives/keyed" "^1.2.2" + "@solid-primitives/resize-observer" "^2.0.26" + "@solid-primitives/storage" "^1.3.11" + "@tanstack/match-sorter-utils" "^8.19.4" + "@tanstack/query-core" "5.103.1" + clsx "^2.1.1" + goober "^2.1.16" + solid-js "^1.9.7" + solid-transition-group "^0.2.3" + superjson "^2.2.2" -"@tanstack/query-devtools@5.100.14": - version "5.100.14" - resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.100.14.tgz#1555c8e1e4ea74db85dd2faaea2b7b50e135faf1" - integrity sha512-g96SmSSQecYTYcyuAMRXr895GplJv01UGt7qttQWPOUyZ5EGz5tbRc589bMc2m5BsPFD6O0PCEAHdbDYNP6UBw== +"@tanstack/react-query-devtools@^5.103.1": + version "5.103.1" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.103.1.tgz#b3548301405de0b1205bb259f12aba6cbf3266ef" + integrity sha512-l6OzwPbDCnuim8w9McFs3dC/rdXTMZBIBFMVrXzNuhUEzWheldubOu+nKRDtPf+1nLRuwavb3We+nNJq/0vV6w== + dependencies: + "@tanstack/query-devtools" "5.103.1" -"@tanstack/react-query-devtools@^5.100.14": - version "5.100.14" - resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.100.14.tgz#0774021fdc0b417a86b67b196d5ffb9820cff10c" - integrity sha512-JkP5VDgKOw3t/QSA1OABRHEqx8BuNs5MfvZRooNqdvN57SzTuGq3fKR1a2IH5rqa5HDLUm+FOXUEnB9ueHiLzg== +"@tanstack/react-query@^5.102.8": + version "5.102.8" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.102.8.tgz#bdc5c24485258e6ae2e7ecac0a4cf58c59937839" + integrity sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A== dependencies: - "@tanstack/query-devtools" "5.100.14" + "@tanstack/query-core" "5.102.8" -"@tanstack/react-query@^5.100.14": - version "5.100.14" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.100.14.tgz#799fe305421fd84bf2f6df40930c859c945b42ab" - integrity sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw== +"@tanstack/react-store@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@tanstack/react-store/-/react-store-0.11.1.tgz#e1e58036ffffa58f5b5d8826c2389f97502fac2c" + integrity sha512-HaIGKI3YLmjBYIvy5DFDY23oNaYZIsTZfngey07Uh5iLVJgM3bIGCnZeOFOqzjFld9JHWcaHJnasD/bKoGKwJQ== dependencies: - "@tanstack/query-core" "5.100.14" + "@tanstack/store" "0.11.1" + use-sync-external-store "^1.6.0" -"@tanstack/react-table@^8.21.3": - version "8.21.3" - resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.21.3.tgz#2c38c747a5731c1a07174fda764b9c2b1fb5e91b" - integrity sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww== +"@tanstack/react-table@^9.2.4": + version "9.2.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-9.2.4.tgz#4324dd0e08d4ca53a433110d8694ad82a4606bc7" + integrity sha512-Rzp1Q4e0/nIgEjmISYR5HeEgLTNtrG+C7NFZf/AbCxPO5hg+zC3yNGwcoECigUk8SFzzvhXbd2rFdtP2ZiGrfA== dependencies: - "@tanstack/table-core" "8.21.3" + "@tanstack/react-store" "^0.11.1" + "@tanstack/table-core" "9.2.4" -"@tanstack/table-core@8.21.3": - version "8.21.3" - resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.21.3.tgz#2977727d8fc8dfa079112d9f4d4c019110f1732c" - integrity sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg== +"@tanstack/store@0.11.1", "@tanstack/store@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@tanstack/store/-/store-0.11.1.tgz#063f634fe3cc925ad83704581a7be75301bec612" + integrity sha512-mzTOBhypOuDJAy/D8n2MfUZ1HFkXnmSETviRyhqEC8LUE7/IZQExOTxMANj3KjTofYTkFNpBY67qaVrT41YccA== + +"@tanstack/table-core@9.2.4": + version "9.2.4" + resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-9.2.4.tgz#8d1b339d6118d306ded4ec8516419320ad2b9e57" + integrity sha512-GwdDyGGr6UXAtubF14yAwcXvdaogqfsQgIk89Suebjxob/Rjq2xvfmXsjDF1rQmKmhHsJm9TOY7myxv3i6geJw== + dependencies: + "@tanstack/store" "^0.11.1" -"@testing-library/dom@^10.4.1": - version "10.4.1" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.1.tgz#d444f8a889e9a46e9a3b4f3b88e0fcb3efb6cf95" - integrity sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg== +"@testing-library/dom@^10.4.2": + version "10.4.2" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.2.tgz#e996827c4e5e1f13589527293b4b3958de2f709f" + integrity sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" @@ -673,10 +843,10 @@ picocolors "1.1.1" pretty-format "^27.0.2" -"@testing-library/jest-dom@^6.9.1": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz#7613a04e146dd2976d24ddf019730d57a89d56c2" - integrity sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA== +"@testing-library/jest-dom@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-7.0.1.tgz#649a9a8b2039f28d29f9f7a46eba9a8b727f811e" + integrity sha512-oMDTC3oA+6CXSO2JZnvOI7CA6oVub6kij5ggk9ohwye5slmkwxYDXcPOVxgMw/RQlticjtO0C1RZkR97HgrWMw== dependencies: "@adobe/css-tools" "^4.4.0" aria-query "^5.0.0" @@ -685,20 +855,13 @@ picocolors "^1.1.1" redent "^3.0.0" -"@testing-library/react@^16.3.2": - version "16.3.2" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.3.2.tgz#672883b7acb8e775fc0492d9e9d25e06e89786d0" - integrity sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g== +"@testing-library/react@^16.3.3": + version "16.3.3" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.3.3.tgz#426907e7716f37038dab8aa69d8f0459f9ec24b2" + integrity sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg== dependencies: "@babel/runtime" "^7.12.5" -"@tybys/wasm-util@^0.10.1": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.2.tgz#12b3a1b33db1f9cad4ddff1f604ab7dd00bf464e" - integrity sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg== - dependencies: - tslib "^2.4.0" - "@types/aria-query@^5.0.1": version "5.0.4" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" @@ -718,9 +881,9 @@ integrity sha512-CefEn/J336TBDp7NX8JqzlDtCBOsm8M3r1Li0gEOt0HOMHF1XemNyrx9lSHjsafcb1yYWybU0N8ZAXuyCaND0w== "@types/debug@^4.0.0": - version "4.1.12" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" - integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + version "4.1.13" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.13.tgz#22d1cc9d542d3593caea764f974306ab36286ee7" + integrity sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw== dependencies: "@types/ms" "*" @@ -737,9 +900,9 @@ "@types/estree" "*" "@types/estree@*", "@types/estree@^1.0.0": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" - integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24" + integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg== "@types/hast@^2.0.0": version "2.3.10" @@ -749,9 +912,9 @@ "@types/unist" "^2" "@types/hast@^3.0.0": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" - integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.5.tgz#48020de4c0e63492f4ca9db42068c108f68b7f8f" + integrity sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g== dependencies: "@types/unist" "*" @@ -779,12 +942,12 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== -"@types/node@*", "@types/node@>=20.0.0", "@types/node@^25.9.1": - version "25.9.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.1.tgz#3bda556db500ae4319c08e7fc9ab94f19013ba0b" - integrity sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg== +"@types/node@*", "@types/node@>=20.0.0", "@types/node@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-26.6.2.tgz#11bfb8e00bafe728d2113e474a7637becc9ab279" + integrity sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g== dependencies: - undici-types ">=7.24.0 <7.24.7" + undici-types "~8.9.0" "@types/parse-json@^4.0.0": version "4.0.2" @@ -801,10 +964,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== -"@types/react-dom@^19.2.3": - version "19.2.3" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c" - integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== +"@types/react-dom@^19.3.0": + version "19.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.3.0.tgz#90294a9266efd928a5266f2110d60d5dba5015d2" + integrity sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q== "@types/react-table@^7.7.20": version "7.7.20" @@ -818,10 +981,17 @@ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@*", "@types/react@>=16.9.11", "@types/react@^19.2.15": - version "19.2.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.15.tgz#9e2c6a4251a290f5c525c3143caa872fa6e01e0d" - integrity sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q== +"@types/react@*", "@types/react@>=16.9.11": + version "19.2.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.18.tgz#eb0b6a1fb635d1a9692d5f84a3495bd8ad153707" + integrity sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w== + dependencies: + csstype "^3.2.2" + +"@types/react@^19.3.0": + version "19.3.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.3.0.tgz#3b3ce8d8c1627fb5ccd4dadd57ef445c5a153b77" + integrity sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg== dependencies: csstype "^3.2.2" @@ -836,9 +1006,9 @@ integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== "@types/warning@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.3.tgz#d1884c8cc4a426d1ac117ca2611bf333834c6798" - integrity sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.4.tgz#ebc0c83180dc83994d902bbd51ab0af8a445b1f9" + integrity sha512-CqN8MnISMwQbLJXO3doBAV4Yw9hx9/Pyr2rZ78+NfaCnhyRA/nKrpyk6E7mKw17ZOaQdLpK9GiUjrqLzBlN3sg== "@types/whatwg-mimetype@^3.0.2": version "3.0.2" @@ -852,6 +1022,106 @@ dependencies: "@types/node" "*" +"@typescript/typescript-aix-ppc64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz#cdc7ce81d60f1e09034960ddfb1fb880d7a776b6" + integrity sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ== + +"@typescript/typescript-darwin-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz#a55fdfcfa58df58d27db2237cde6a5c1e35a7235" + integrity sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA== + +"@typescript/typescript-darwin-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz#38d1c9172800a91d707bec64d2a370a016634db4" + integrity sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA== + +"@typescript/typescript-freebsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz#f1ff8810030b35d2b5be0db6a2dc650460ea94fa" + integrity sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ== + +"@typescript/typescript-freebsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz#3d86b03f353c5b1ba95162eb6ce35533bfc294bd" + integrity sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw== + +"@typescript/typescript-linux-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz#d9334d96d6dac6ff85da9c865588948de939e91f" + integrity sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ== + +"@typescript/typescript-linux-arm@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz#ad94b41e1aee2a4dcc6a298c7b67c43345fde32e" + integrity sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ== + +"@typescript/typescript-linux-loong64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz#2965aee4fc873360139d893daafe6397a29138ad" + integrity sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ== + +"@typescript/typescript-linux-mips64el@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz#1a887a311bed3a833f80bfd4a9ed37c271936cf0" + integrity sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA== + +"@typescript/typescript-linux-ppc64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz#8b63c9b2f445b393eb4e43ec21da225dade3577d" + integrity sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA== + +"@typescript/typescript-linux-riscv64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz#b6e8a35c289b3ea97a92a41d461aaeed0d3b36e1" + integrity sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ== + +"@typescript/typescript-linux-s390x@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz#2ef96693be4861f6d17965427e5b009cbbed1a3e" + integrity sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw== + +"@typescript/typescript-linux-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz#73269cb0baba50aea0ca060445a6b88e583f1ce2" + integrity sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A== + +"@typescript/typescript-netbsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz#3a3649f97fafa210b4e6e3798c15e06605c8a901" + integrity sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA== + +"@typescript/typescript-netbsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz#47ec59491a40c470d2807dc4d2b825528fd979ab" + integrity sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA== + +"@typescript/typescript-openbsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz#796be8da0bd989d8a3fb96f2801e38a8365b4baf" + integrity sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ== + +"@typescript/typescript-openbsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz#d37fe2a729eb942c076c454ee7f1815faf7d560f" + integrity sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg== + +"@typescript/typescript-sunos-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz#aba8d3464c3565a7044789baba96916bd4ab2c88" + integrity sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g== + +"@typescript/typescript-win32-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz#b9de50a17196383f62620b5f9d0a2f34ad3b60d7" + integrity sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ== + +"@typescript/typescript-win32-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz#cf3b7b0d6ce5635daca4c8e01c189cdcde47ec3c" + integrity sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g== + "@uiw/react-textarea-code-editor@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@uiw/react-textarea-code-editor/-/react-textarea-code-editor-3.1.1.tgz#8ca1b706a3081a51c68bc0df91c9c3cdadd9944e" @@ -862,74 +1132,74 @@ rehype-prism-plus "2.0.0" "@ungap/structured-clone@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" - integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + version "1.3.3" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.3.tgz#094041e1a4cb1987f038335421281ac8be390bcc" + integrity sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg== -"@vitejs/plugin-react@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz#f70cb8ed0ce225dbc3055d78070f820d8aa35eda" - integrity sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg== +"@vitejs/plugin-react@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz#47fa1a2f956e88eaf778ebf65ddce8e2b36597e7" + integrity sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw== dependencies: - "@rolldown/pluginutils" "^1.0.0" + "@rolldown/pluginutils" "^1.0.1" -"@vitest/expect@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.7.tgz#dc2918d51b54fa24ac5b4e7e802ef7440a11027f" - integrity sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w== +"@vitest/expect@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.11.tgz#5f580d1f9cdbba314dbf23b2d911f8eb23878f5f" + integrity sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw== dependencies: "@standard-schema/spec" "^1.1.0" "@types/chai" "^5.2.2" - "@vitest/spy" "4.1.7" - "@vitest/utils" "4.1.7" + "@vitest/spy" "4.1.11" + "@vitest/utils" "4.1.11" chai "^6.2.2" tinyrainbow "^3.1.0" -"@vitest/mocker@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.7.tgz#05c5b42968b56057c40ea3e4546f3227cf1bf6fc" - integrity sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA== +"@vitest/mocker@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.11.tgz#8e2906361bc5dfa271757a858ae80643118fcbb4" + integrity sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ== dependencies: - "@vitest/spy" "4.1.7" + "@vitest/spy" "4.1.11" estree-walker "^3.0.3" magic-string "^0.30.21" -"@vitest/pretty-format@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.7.tgz#86b37ea96d4c5bd1357be66982e60a89a343c1bb" - integrity sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw== +"@vitest/pretty-format@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.11.tgz#8b28eb8240771d6ea970e33beaeb41384b51868e" + integrity sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw== dependencies: tinyrainbow "^3.1.0" -"@vitest/runner@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.7.tgz#a7c465a76c0edc7deb1e8927dad452b71c5797b5" - integrity sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw== +"@vitest/runner@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.11.tgz#bfbad98c8d6c3f1fb4df12056ad569821ff77f21" + integrity sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw== dependencies: - "@vitest/utils" "4.1.7" + "@vitest/utils" "4.1.11" pathe "^2.0.3" -"@vitest/snapshot@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.7.tgz#03ca7bed0cb3f2ce37de9feee7a159ba5d4893a4" - integrity sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw== +"@vitest/snapshot@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.11.tgz#df461eb165924a3155986dde68e13360f53f3d4c" + integrity sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog== dependencies: - "@vitest/pretty-format" "4.1.7" - "@vitest/utils" "4.1.7" + "@vitest/pretty-format" "4.1.11" + "@vitest/utils" "4.1.11" magic-string "^0.30.21" pathe "^2.0.3" -"@vitest/spy@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.7.tgz#459de6b5f2c80cb589e612b2fa8170a33393dee9" - integrity sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q== +"@vitest/spy@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.11.tgz#0add45cae953afed9c88f98e2f6fc9164558c32a" + integrity sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA== -"@vitest/utils@4.1.7": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.7.tgz#8d2350588f7054246f24d0dbadffbef5d3a5caff" - integrity sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw== +"@vitest/utils@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.11.tgz#9b27a4293b827942b223539bfab1bd9f7eada31b" + integrity sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ== dependencies: - "@vitest/pretty-format" "4.1.7" + "@vitest/pretty-format" "4.1.11" convert-source-map "^2.0.0" tinyrainbow "^3.1.0" @@ -943,6 +1213,13 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +aria-hidden@^1.2.3: + version "1.2.6" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a" + integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== + dependencies: + tslib "^2.0.0" + aria-query@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" @@ -979,10 +1256,12 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bootstrap@5.3.7: - version "5.3.7" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.7.tgz#8640065036124d961d885d80b5945745e1154d90" - integrity sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw== +buffer-image-size@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/buffer-image-size/-/buffer-image-size-0.6.4.tgz#357e8173e951ced3b5a2785c695993aa29dbcac4" + integrity sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ== + dependencies: + "@types/node" "*" buffer@^6.0.3: version "6.0.3" @@ -1039,7 +1318,7 @@ classnames@^2.3.2, classnames@^2.5.1: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -clsx@^2.1.1: +clsx@^2.0.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -1064,6 +1343,11 @@ cookie@^1.0.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.1.1.tgz#3bb9bdfc82369db9c2f69c93c9c3ceb310c88b3c" integrity sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ== +copy-anything@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-4.1.1.tgz#2734bcffa1f01f8e2afb2232f1ee31cd5fcc6834" + integrity sha512-AoT6Imdr98feSpFfmFwTFN73ccdr7uFPf27cBCgYvyyRyn1BzLRxMvrHNmwXO5LJMddRy4Rdhw2b1h7vSMKsEw== + cosmiconfig@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -1075,25 +1359,25 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -country-flag-icons@^1.6.17: - version "1.6.17" - resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.6.17.tgz#875cf35eb2a0d7fcb0f07166fed9fc65863e03f8" - integrity sha512-Nmik0289ZVZSI3c7mJR/amg6DyY7Z59b0sTFSKayeX72mHfPzCPJygwJs2pYgQULzuAyWeCUgwAJ+Dq8OR+JFw== +country-flag-icons@^1.6.20: + version "1.6.20" + resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.6.20.tgz#aa6f36104568993f9cd43e7da283f9b7d0a802cc" + integrity sha512-py8JiEKzjhYw6HPJ0L7SxLgCYim36UPRTZX43/kqGueUCZLSvnrqAiwW8HtQibur7mdkFQUkjOgdK+o/9FBtaw== css.escape@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== -csstype@^3.0.2, csstype@^3.2.2: +csstype@^3.0.2, csstype@^3.1.0, csstype@^3.2.2: version "3.2.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== -date-fns@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.3.0.tgz#95663b78f2be5ce664eb6606d94582acc39c77ba" - integrity sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ== +date-fns@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.4.0.tgz#806539edf45c616b2b76b5f78b88c56ed3c7e036" + integrity sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w== debug@^4.0.0, debug@^4.3.1: version "4.4.3" @@ -1109,10 +1393,10 @@ decode-named-character-reference@^1.0.0: dependencies: character-entities "^2.0.0" -decode-uri-component@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.4.1.tgz#2ac4859663c704be22bf7db760a1494a49ab2cc5" - integrity sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ== +decode-uri-component@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.5.0.tgz#4592fa1e1d640ec5e2760e2e168ad2ab5f2c9da1" + integrity sha512-1BiQVoK8C9gUbQU6NzAtO/tkz2qOFpEObMWpcFvhx4fYnj4Oc5yzaJN/LD36ihkVUdXyh5ZekzX+yM+ty/SrPg== deepmerge@^2.1.1: version "2.2.1" @@ -1171,10 +1455,15 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-module-lexer@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.1.0.tgz#1dfcbb5ea3bbfb63f28e1fc3676c3676d1c9624c" - integrity sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ== + version "2.3.2" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.3.2.tgz#311fa4f40168c1975c505477c51b23234d41ad55" + integrity sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw== escape-string-regexp@^4.0.0: version "4.0.0" @@ -1194,9 +1483,9 @@ estree-walker@^3.0.3: "@types/estree" "^1.0.0" expect-type@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" - integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + version "1.4.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.4.0.tgz#24edf7f0cc69a44d008567ba4594ab96f3c3a3d6" + integrity sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA== extend@^3.0.0: version "3.0.2" @@ -1260,27 +1549,33 @@ generate-password-browser@^1.1.0: buffer "^6.0.3" randombytes "^2.0.5" +goober@^2.1.16: + version "2.1.19" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.19.tgz#a4b4dcdbba9325b8c4d7380099f9f281f27c6a6f" + integrity sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg== + graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -happy-dom@^20.9.0: - version "20.9.0" - resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-20.9.0.tgz#22fa4f2b8a34d2fbd0fb43eb48227e4bf8e206e8" - integrity sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ== +happy-dom@^20.14.5: + version "20.14.5" + resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-20.14.5.tgz#d76cfbb926ebde0575deb3bf92cb3e6bb88b8176" + integrity sha512-x/RzkpWO40bTjIoT30iQtt64FLLmH/iRcUCN2X//bLx7H3ifkdfPXyqsro/OYtqzIAhiLMMA7mmiOR9C3NOKjQ== dependencies: "@types/node" ">=20.0.0" "@types/whatwg-mimetype" "^3.0.2" "@types/ws" "^8.18.1" + buffer-image-size "^0.6.4" entities "^7.0.1" whatwg-mimetype "^3.0.0" - ws "^8.18.3" + ws "^8.21.0" -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== +hasown@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== dependencies: function-bind "^1.1.2" @@ -1426,9 +1721,9 @@ ieee754@^1.2.1: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== immutable@^5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.5.tgz#93ee4db5c2a9ab42a4a783069f3c5d8847d40165" - integrity sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A== + version "5.1.9" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.9.tgz#ac23c3a01992ab665e14ac9ffff298f28cd74a0c" + integrity sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg== import-fresh@^3.2.1: version "3.3.1" @@ -1448,13 +1743,13 @@ inline-style-parser@0.2.7: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.7.tgz#b1fc68bfc0313b8685745e4464e37f9376b9c909" integrity sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA== -intl-messageformat@11.2.7: - version "11.2.7" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-11.2.7.tgz#1d922a7df8964ec496c56f62928ef2134674bdae" - integrity sha512-+q6Ktg119nULZEpZ8YTuGOst9MyEzFtjD63FTGBlN1mLz0Z/MOUYDIvnpVKwq17eezIEh+cfJIebfJoCetpiNw== +intl-messageformat@11.2.14: + version "11.2.14" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-11.2.14.tgz#610e4a21511d85dc06634424409d60bb1e9e441f" + integrity sha512-9f2VD1HFuxUvMw0RxsaP8WmMns6JRTnsNB/zghTFrp11ZktiXWwVDeZBPQchBKEmo+Gx/ZhxI7Qht7YglFD4PA== dependencies: - "@formatjs/fast-memoize" "3.1.5" - "@formatjs/icu-messageformat-parser" "3.5.10" + "@formatjs/fast-memoize" "3.1.7" + "@formatjs/icu-messageformat-parser" "3.5.17" invariant@^2.2.4: version "2.2.4" @@ -1482,11 +1777,11 @@ is-arrayish@^0.2.1: integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-core-module@^2.16.1: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + version "2.16.2" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.2.tgz#3e07450a8080ebce3fbf0cac494f4d2ab324e082" + integrity sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA== dependencies: - hasown "^2.0.2" + hasown "^2.0.3" is-decimal@^2.0.0: version "2.0.1" @@ -1535,79 +1830,79 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -lightningcss-android-arm64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz#f033885116dfefd9c6f54787523e3514b61e1968" - integrity sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg== - -lightningcss-darwin-arm64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz#50b71871b01c8199584b649e292547faea7af9b5" - integrity sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ== - -lightningcss-darwin-x64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz#35f3e97332d130b9ca181e11b568ded6aebc6d5e" - integrity sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w== - -lightningcss-freebsd-x64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz#9777a76472b64ed6ff94342ad64c7bafd794a575" - integrity sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig== - -lightningcss-linux-arm-gnueabihf@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz#13ae652e1ab73b9135d7b7da172f666c410ad53d" - integrity sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw== - -lightningcss-linux-arm64-gnu@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz#417858795a94592f680123a1b1f9da8a0e1ef335" - integrity sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ== - -lightningcss-linux-arm64-musl@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz#6be36692e810b718040802fd809623cffe732133" - integrity sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg== - -lightningcss-linux-x64-gnu@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz#0b7803af4eb21cfd38dd39fe2abbb53c7dd091f6" - integrity sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA== - -lightningcss-linux-x64-musl@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz#88dc8ba865ddddb1ac5ef04b0f161804418c163b" - integrity sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg== - -lightningcss-win32-arm64-msvc@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz#4f30ba3fa5e925f5b79f945e8cc0d176c3b1ab38" - integrity sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw== - -lightningcss-win32-x64-msvc@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz#141aa5605645064928902bb4af045fa7d9f4220a" - integrity sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q== - -lightningcss@^1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.32.0.tgz#b85aae96486dcb1bf49a7c8571221273f4f1e4a9" - integrity sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ== +lightningcss-android-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz#9a6841f88ae50fc83502903892b41af41bc2b907" + integrity sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg== + +lightningcss-darwin-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz#c0f2c31c0bfd19fa4dd3f18e957a1f1a152097d6" + integrity sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg== + +lightningcss-darwin-x64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz#cb0705965acb538c6683949ce6925fb3cdf7c361" + integrity sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ== + +lightningcss-freebsd-x64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz#763538828b26bab2680dadafcc84ee78b0eb502b" + integrity sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg== + +lightningcss-linux-arm-gnueabihf@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz#6862e3176a331aedbdec1ed352b4d7d0dd0784de" + integrity sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ== + +lightningcss-linux-arm64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz#c6a3a2ed15141daf6bdc2628930f8e39bdf473aa" + integrity sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg== + +lightningcss-linux-arm64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz#7fa1334971fc82845f9827df6ef8a0b20914bac6" + integrity sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ== + +lightningcss-linux-x64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz#8b927862ea8c2bbc6831a46509244b50d9936e55" + integrity sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg== + +lightningcss-linux-x64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz#0c525bb077dfd94404c059cfe42dad797e96aeaf" + integrity sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw== + +lightningcss-win32-arm64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz#850ee1103dac989cfab50e3ac22d1a69e394e63d" + integrity sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA== + +lightningcss-win32-x64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz#e343ae152eed3609dc6e11949d1a3bf39a1c946f" + integrity sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA== + +lightningcss@^1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.33.0.tgz#c08867d71a79385c6e190214fd72fef3e5f95f0b" + integrity sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA== dependencies: detect-libc "^2.0.3" optionalDependencies: - lightningcss-android-arm64 "1.32.0" - lightningcss-darwin-arm64 "1.32.0" - lightningcss-darwin-x64 "1.32.0" - lightningcss-freebsd-x64 "1.32.0" - lightningcss-linux-arm-gnueabihf "1.32.0" - lightningcss-linux-arm64-gnu "1.32.0" - lightningcss-linux-arm64-musl "1.32.0" - lightningcss-linux-x64-gnu "1.32.0" - lightningcss-linux-x64-musl "1.32.0" - lightningcss-win32-arm64-msvc "1.32.0" - lightningcss-win32-x64-msvc "1.32.0" + lightningcss-android-arm64 "1.33.0" + lightningcss-darwin-arm64 "1.33.0" + lightningcss-darwin-x64 "1.33.0" + lightningcss-freebsd-x64 "1.33.0" + lightningcss-linux-arm-gnueabihf "1.33.0" + lightningcss-linux-arm64-gnu "1.33.0" + lightningcss-linux-arm64-musl "1.33.0" + lightningcss-linux-x64-gnu "1.33.0" + lightningcss-linux-x64-musl "1.33.0" + lightningcss-win32-arm64-msvc "1.33.0" + lightningcss-win32-x64-msvc "1.33.0" lines-and-columns@^1.1.6: version "1.2.4" @@ -1654,9 +1949,9 @@ magic-string@^0.30.21: "@jridgewell/sourcemap-codec" "^1.5.5" mdast-util-from-markdown@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz#4850390ca7cf17413a9b9a0fbefcd1bc0eb4160a" - integrity sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== + version "2.0.3" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz#c95822b91aab75f18a4cbe8b2f51b873ed2cf0c7" + integrity sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" @@ -1967,10 +2262,10 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.3.12: - version "3.3.12" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.12.tgz#ab3d912e217a6d0a514f00a72a16543a28982c05" - integrity sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ== +nanoid@^3.3.18: + version "3.3.19" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.19.tgz#336d4aa4bcd4fb24d2cddede7ffeae40bec03f0a" + integrity sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug== node-addon-api@^7.0.0: version "7.1.1" @@ -1991,9 +2286,9 @@ object-assign@^4.1.1: integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== obug@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.1.tgz#2cba74ff241beb77d63055ddf4cd1e9f90b538be" - integrity sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ== + version "2.1.4" + resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.4.tgz#9090d8a548a522517915d2aa6aae907197ac6cf8" + integrity sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA== parent-module@^1.0.0: version "1.0.1" @@ -2067,22 +2362,22 @@ picocolors@1.1.1, picocolors@^1.1.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^4.0.3, picomatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" - integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== +picomatch@^4.0.3, picomatch@^4.0.4, picomatch@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.7.tgz#6313360034ccb36b3dc61ecbdff78121f90fe21f" + integrity sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA== postcss-simple-vars@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz#836b3097a54dcd13dbd3c36a5dbdd512fad2954c" integrity sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A== -postcss@^8.5.15: - version "8.5.15" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c" - integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A== +postcss@^8.5.28: + version "8.5.28" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.28.tgz#da4563a99a06e62d6c1cd1acae363224bcaed6e9" + integrity sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A== dependencies: - nanoid "^3.3.12" + nanoid "^3.3.18" picocolors "^1.1.1" source-map-js "^1.2.1" @@ -2127,16 +2422,21 @@ property-information@^6.0.0: integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== property-information@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.1.0.tgz#b622e8646e02b580205415586b40804d3e8bfd5d" - integrity sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ== + version "7.2.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.2.0.tgz#0809b34264e995c0bfcd3227028a1e35210af80a" + integrity sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg== + +qrcode-generator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-2.0.4.tgz#e8b3f30922577eba52078aa9c0d5a2a74fe1fd94" + integrity sha512-mZSiP6RnbHl4xL2Ap5HfkjLnmxfKcPWpWe/c+5XxCuetEenqmNFf1FH/ftXPCtFG5/TDobjsjz6sSNL0Sr8Z9g== -query-string@^9.3.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.3.1.tgz#d0c93e6c7fb7c17bdf04aa09e382114580ede270" - integrity sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw== +query-string@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.5.1.tgz#aecdc091d3dc7ce293eed83957e220d523a3d0f7" + integrity sha512-/zO3RwuRCMTIcEgq6YMv4OrtEE1XzBG7w5N6zc6ydYnkWYOWsnLI/5894hYEzfESfMOT4cHCsRTIdxsSl1KjGg== dependencies: - decode-uri-component "^0.4.1" + decode-uri-component "^0.5.0" filter-obj "^5.1.0" split-on-first "^3.0.0" @@ -2154,6 +2454,21 @@ randombytes@^2.0.5: dependencies: safe-buffer "^5.1.0" +react-aria@^3.48.0: + version "3.51.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.51.0.tgz#b8129df769eda51a0f92d256fddcc105badf6ed7" + integrity sha512-AyWLw0XR38cFPwBu/ErgGaVrc5dupLEKmRlMXTGvFKOtbaGRQ2+yQJkjVhpdHhoRhU4+G+tJDFeHDTS8tK3bfQ== + dependencies: + "@internationalized/date" "^3.12.3" + "@internationalized/number" "^3.6.7" + "@internationalized/string" "^3.2.10" + "@react-types/shared" "^3.36.1" + "@swc/helpers" "^0.5.0" + aria-hidden "^1.2.3" + clsx "^2.0.0" + react-stately "3.49.0" + use-sync-external-store "^1.6.0" + react-bootstrap@^2.10.10: version "2.10.10" resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-2.10.10.tgz#be0b0d951a69987152d75c0e6986c80425efdf21" @@ -2173,26 +2488,26 @@ react-bootstrap@^2.10.10: uncontrollable "^7.2.1" warning "^4.0.3" -react-dom@^19.2.6: - version "19.2.6" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.6.tgz#44a81b0bcca22da814c00847d09d01c8615529b7" - integrity sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g== +react-dom@^19.3.0: + version "19.3.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.3.0.tgz#a0ff19161d7f4e9be5469a07278b0c06e00f9001" + integrity sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q== dependencies: - scheduler "^0.27.0" + scheduler "^0.28.0" react-fast-compare@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== -react-intl@^10.1.9: - version "10.1.9" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-10.1.9.tgz#e256f0c28a049d391d421bf658e49fe137fb2cdf" - integrity sha512-FOWpTmwnZnAfz8JegRzyGnjUiuzLW3xJFjp/o8VR4HZAQ+Eg++YaeMhoUULLY+LMx7gZm3czaZEqcU4hntwerw== +react-intl@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-10.2.0.tgz#576783362ada9bc9a8ced594b1d8ff1225a08f2f" + integrity sha512-b7wiqmo/fWQZ5Et7f8Qsh58rD+6STV/KrX4NuVjmpGFAxk2vqgEwGKDlW0uRfWG2mg4zt7sWnxvOBfLPMDkMYA== dependencies: - "@formatjs/icu-messageformat-parser" "3.5.10" - "@formatjs/intl" "4.1.12" - intl-messageformat "11.2.7" + "@formatjs/icu-messageformat-parser" "3.5.17" + "@formatjs/intl" "4.2.0" + intl-messageformat "11.2.14" react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0: version "16.13.1" @@ -2226,17 +2541,25 @@ react-markdown@^10.1.0: unist-util-visit "^5.0.0" vfile "^6.0.0" -react-router-dom@^7.15.1: - version "7.15.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.15.1.tgz#cf5aee65a44e407a17a2e9718d5350482b1e281f" - integrity sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg== +react-qr-code@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.2.0.tgz#301b5dc4d2fed503e1e313f237a7f32c1885152a" + integrity sha512-e5nS0UUN22K3Nf8KBRUzemfdJ6OmnN5w+kbnj1lvJaol9RyVRFeGl05bCkxSN2ZegbLxjjYjX1+mmAoX9+fAhw== dependencies: - react-router "7.15.1" + prop-types "^15.8.1" + qrcode-generator "^2.0.4" + +react-router-dom@^7.18.4: + version "7.18.4" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.18.4.tgz#07b72b8aab2d80af847425107f966f1688c703d0" + integrity sha512-yrfmJHIpDG7taCpqKjT1G5B6q3O2K+RN8/fgNf0lTjCwiPbQ0ei6vXX9ZjQR+7ld8Tr7Z5xmyMnZ8YJrphWQUw== + dependencies: + react-router "7.18.4" -react-router@7.15.1: - version "7.15.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.15.1.tgz#0a12fece05887a47c54970480745385c793bcaac" - integrity sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A== +react-router@7.18.4: + version "7.18.4" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.18.4.tgz#dc30cbb27e936f06d9e1d75ab648b317deb698a4" + integrity sha512-PUPQcMhMGRAslLcvtlPz/kmzBEWPhLdgLFrL7pLNepBL6dX0lWj4WD2cUYVgYCuT3jxvghYFg81cDTj44DhetQ== dependencies: cookie "^1.0.1" set-cookie-parser "^2.6.0" @@ -2256,6 +2579,18 @@ react-select@^5.10.2: react-transition-group "^4.3.0" use-isomorphic-layout-effect "^1.2.0" +react-stately@3.49.0: + version "3.49.0" + resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.49.0.tgz#bc7fda7d0245e2a1239a8f0451950b27639d0e17" + integrity sha512-13iNq2KzBrRAzxRc+n53hgROfIistiYY/sPtIhCw1qUB7/kmo+X1xEU2uiS5zcCIrc55AUPwoHqOIIpKWSwB9A== + dependencies: + "@internationalized/date" "^3.12.3" + "@internationalized/number" "^3.6.7" + "@internationalized/string" "^3.2.10" + "@react-types/shared" "^3.36.1" + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.6.0" + react-toastify@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.1.0.tgz#3d3c73a44d5cac868ee9a52e0f90dd706532c4a4" @@ -2273,15 +2608,15 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^19.2.6: - version "19.2.6" - resolved "https://registry.yarnpkg.com/react/-/react-19.2.6.tgz#3dadb8e12b2a7934c1d5317973e5dce1301f9a4d" - integrity sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q== +react@^19.3.0: + version "19.3.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.3.0.tgz#e20aa3a14687075ce863351b5878b0608c3fbfb2" + integrity sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog== readdirp@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-5.0.0.tgz#fbf1f71a727891d685bb1786f9ba74084f6e2f91" - integrity sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ== + version "5.1.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-5.1.1.tgz#520bca06f9d1ae1b96cc0800dbe84b983d19422c" + integrity sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA== redent@^3.0.0: version "3.0.0" @@ -2362,16 +2697,22 @@ remark-rehype@^11.0.0: unified "^11.0.0" vfile "^6.0.0" +remove-accents@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" + integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve@^1.19.0: - version "1.22.11" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" - integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + version "1.22.12" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.12.tgz#f5b2a680897c69c238a13cd16b15671f8b73549f" + integrity sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA== dependencies: + es-errors "^1.3.0" is-core-module "^2.16.1" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -2381,34 +2722,34 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rolldown@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.0.2.tgz#ea2c786c5f063d08fd22b49e51997f15ec532bbd" - integrity sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g== +rolldown@~1.2.6: + version "1.2.9" + resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.2.9.tgz#b449d73b7aeaf0097adfc25967a76fa1bf304c56" + integrity sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg== dependencies: - "@oxc-project/types" "=0.132.0" + "@oxc-project/types" "=0.150.0" "@rolldown/pluginutils" "^1.0.0" optionalDependencies: - "@rolldown/binding-android-arm64" "1.0.2" - "@rolldown/binding-darwin-arm64" "1.0.2" - "@rolldown/binding-darwin-x64" "1.0.2" - "@rolldown/binding-freebsd-x64" "1.0.2" - "@rolldown/binding-linux-arm-gnueabihf" "1.0.2" - "@rolldown/binding-linux-arm64-gnu" "1.0.2" - "@rolldown/binding-linux-arm64-musl" "1.0.2" - "@rolldown/binding-linux-ppc64-gnu" "1.0.2" - "@rolldown/binding-linux-s390x-gnu" "1.0.2" - "@rolldown/binding-linux-x64-gnu" "1.0.2" - "@rolldown/binding-linux-x64-musl" "1.0.2" - "@rolldown/binding-openharmony-arm64" "1.0.2" - "@rolldown/binding-wasm32-wasi" "1.0.2" - "@rolldown/binding-win32-arm64-msvc" "1.0.2" - "@rolldown/binding-win32-x64-msvc" "1.0.2" - -rooks@^9.8.0: - version "9.8.0" - resolved "https://registry.yarnpkg.com/rooks/-/rooks-9.8.0.tgz#bf4790f1d379cb9d2f60570202e39d297ed88f8a" - integrity sha512-S6FqnmERx5zgl8ZUEcnyTe1jgjwE5xeFCgOV4bzgQHKp26P7YA7uPnzzOgacojtoX6E7pQTcewSGqN83wVyz+g== + "@rolldown/binding-android-arm-eabi" "1.2.9" + "@rolldown/binding-android-arm64" "1.2.9" + "@rolldown/binding-darwin-arm64" "1.2.9" + "@rolldown/binding-darwin-x64" "1.2.9" + "@rolldown/binding-freebsd-x64" "1.2.9" + "@rolldown/binding-linux-arm-gnueabihf" "1.2.9" + "@rolldown/binding-linux-arm64-gnu" "1.2.9" + "@rolldown/binding-linux-arm64-musl" "1.2.9" + "@rolldown/binding-linux-ppc64-gnu" "1.2.9" + "@rolldown/binding-linux-s390x-gnu" "1.2.9" + "@rolldown/binding-linux-x64-gnu" "1.2.9" + "@rolldown/binding-linux-x64-musl" "1.2.9" + "@rolldown/binding-openharmony-arm64" "1.2.9" + "@rolldown/binding-win32-arm64-msvc" "1.2.9" + "@rolldown/binding-win32-x64-msvc" "1.2.9" + +rooks@^9.9.0: + version "9.9.0" + resolved "https://registry.yarnpkg.com/rooks/-/rooks-9.9.0.tgz#3a1437d55bb56f0787f1e90109471c6f065dec9a" + integrity sha512-ygSdaIlRiBNQmaJUYn/f66irkAIvcAFAsxwMFOV8UA9OLg0yokLgUHN73bOsTgSxrZo8+hjbr1Gdo3IYnIHZuw== dependencies: fast-deep-equal "^3.1.3" lodash.debounce "^4.0.8" @@ -2422,10 +2763,10 @@ safe-buffer@^5.1.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -sass@^1.100.0: - version "1.100.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.100.0.tgz#b4cab1bed286fe22ac6c879c514f71cd36aa06c8" - integrity sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ== +sass@^1.104.1: + version "1.104.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.104.1.tgz#29a4bdb33c48a8bb656e300a33afcafbfcbc8491" + integrity sha512-yDA+1aIG3EHgN4V/BvuhCvu61FF6hEd4e+9DxikUm9U0CAGuvdIZ/UYy7qbOxjhbbWQraoyLlMuzdRGOSV5Bmw== dependencies: chokidar "^5.0.0" immutable "^5.1.5" @@ -2433,10 +2774,20 @@ sass@^1.100.0: optionalDependencies: "@parcel/watcher" "^2.4.1" -scheduler@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd" - integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q== +scheduler@^0.28.0: + version "0.28.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.28.0.tgz#03d3ca348aeaf8b7502f64468f217b27523f9695" + integrity sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw== + +seroval-plugins@~1.5.4: + version "1.5.6" + resolved "https://registry.yarnpkg.com/seroval-plugins/-/seroval-plugins-1.5.6.tgz#7bca495aceb5b2428b9cb44b4b09e67c2de1c948" + integrity sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ== + +seroval@~1.5.4: + version "1.5.6" + resolved "https://registry.yarnpkg.com/seroval/-/seroval-1.5.6.tgz#68d4f6a05c3bde25daaaea6b7220146ff42353ca" + integrity sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA== set-cookie-parser@^2.6.0: version "2.7.2" @@ -2453,6 +2804,37 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +solid-js@^1.9.7: + version "1.9.15" + resolved "https://registry.yarnpkg.com/solid-js/-/solid-js-1.9.15.tgz#209cbd4e0c7108d1e9bd1537ea7f91e03277a763" + integrity sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg== + dependencies: + csstype "^3.1.0" + seroval "~1.5.4" + seroval-plugins "~1.5.4" + +solid-presence@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/solid-presence/-/solid-presence-0.2.0.tgz#1f92958d549fba5ebc5905b33d02ba854132c68d" + integrity sha512-YM92o+jvpzX3XGaD4rLYmq/Kc2ZVh47GSCLEufHBFQQIurvZTs8SoGJxO8BJGNDxBKdcS8F3dYhW1SDXp4BNjA== + dependencies: + "@corvu/utils" "~0.4.2" + +solid-prevent-scroll@^0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/solid-prevent-scroll/-/solid-prevent-scroll-0.1.11.tgz#4d92aeff067ec3c10e3461b850e09b5c9f9ab4a6" + integrity sha512-2PComVCDHaQN/5t7ogEqUYeHasritZKXZ8Sb/VLkl0Web8o9YhEwOo8LSujJEahvMlYCNyKt0zRJeHldOAeWZg== + dependencies: + "@corvu/utils" "~0.4.2" + +solid-transition-group@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/solid-transition-group/-/solid-transition-group-0.2.3.tgz#ef441d9e4620cddc4d29cdbc958b09f94db515c4" + integrity sha512-iB72c9N5Kz9ykRqIXl0lQohOau4t0dhel9kjwFvx81UZJbVwaChMuBuyhiZmK24b8aKEK0w3uFM96ZxzcyZGdg== + dependencies: + "@solid-primitives/refs" "^1.0.5" + "@solid-primitives/transition-group" "^1.0.2" + "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" @@ -2479,9 +2861,9 @@ stackback@0.0.2: integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== std-env@^4.0.0-rc.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-4.1.0.tgz#45899abc590d86d682e87f0acd1033a75084cd3f" - integrity sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-4.2.0.tgz#8ebe0ec60485668ab47227b312f4254cdf80c9d3" + integrity sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw== stringify-entities@^4.0.0: version "4.0.4" @@ -2517,6 +2899,13 @@ stylis@4.2.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== +superjson@^2.2.2: + version "2.2.6" + resolved "https://registry.yarnpkg.com/superjson/-/superjson-2.2.6.tgz#a223a3a988172a5f9656e2063fe5f733af40d099" + integrity sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA== + dependencies: + copy-anything "^4" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -2538,27 +2927,27 @@ tinybench@^2.9.0: integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== tinyexec@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.2.tgz#bdd2737fe2ba40bd6f918ae26642f264b99ca251" - integrity sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.3.0.tgz#aacc1dbb1d4e93e6ad8dd64944e09f9ad147a474" + integrity sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ== -tinyglobby@^0.2.15, tinyglobby@^0.2.16: - version "0.2.16" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.16.tgz#1c3b7eb953fce42b226bc5a1ee06428281aff3d6" - integrity sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg== +tinyglobby@^0.2.15, tinyglobby@^0.2.17: + version "0.2.17" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" + integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== dependencies: fdir "^6.5.0" picomatch "^4.0.4" tinyrainbow@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz#1d8a623893f95cf0a2ddb9e5d11150e191409421" - integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw== + version "3.1.1" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.1.tgz#c0168387d3d8d70b6b3c2c0936de5fee738cea20" + integrity sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw== -tmp@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.6.tgz#0dfac10fd09a9319288eb0e8f0ed524604e183b4" - integrity sha512-5sJPdPjfI5Kx+qbrDesxkglRBxW//g7hCsqspEjwkewGvBMGIKMOTKzLt1hFVJzyadba3lDUN20O9qhvbQUSTA== +tmp@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.7.tgz#26f4db11d1601ce8012dcb8a798ece1c06a99059" + integrity sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw== trim-lines@^3.0.0: version "3.0.1" @@ -2570,15 +2959,36 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== -tslib@^2.0.0, tslib@^2.4.0, tslib@^2.8.0: +tslib@^2.0.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -typescript@6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" - integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== +typescript@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-7.0.2.tgz#9ec773d7954a8c182c17cc5bbd575aa28bc51582" + integrity sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA== + optionalDependencies: + "@typescript/typescript-aix-ppc64" "7.0.2" + "@typescript/typescript-darwin-arm64" "7.0.2" + "@typescript/typescript-darwin-x64" "7.0.2" + "@typescript/typescript-freebsd-arm64" "7.0.2" + "@typescript/typescript-freebsd-x64" "7.0.2" + "@typescript/typescript-linux-arm" "7.0.2" + "@typescript/typescript-linux-arm64" "7.0.2" + "@typescript/typescript-linux-loong64" "7.0.2" + "@typescript/typescript-linux-mips64el" "7.0.2" + "@typescript/typescript-linux-ppc64" "7.0.2" + "@typescript/typescript-linux-riscv64" "7.0.2" + "@typescript/typescript-linux-s390x" "7.0.2" + "@typescript/typescript-linux-x64" "7.0.2" + "@typescript/typescript-netbsd-arm64" "7.0.2" + "@typescript/typescript-netbsd-x64" "7.0.2" + "@typescript/typescript-openbsd-arm64" "7.0.2" + "@typescript/typescript-openbsd-x64" "7.0.2" + "@typescript/typescript-sunos-x64" "7.0.2" + "@typescript/typescript-win32-arm64" "7.0.2" + "@typescript/typescript-win32-x64" "7.0.2" uncontrollable@^7.2.1: version "7.2.1" @@ -2595,10 +3005,10 @@ uncontrollable@^8.0.4: resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-8.0.4.tgz#a0a8307f638795162fafd0550f4a1efa0f8c5eb6" integrity sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ== -"undici-types@>=7.24.0 <7.24.7": - version "7.24.6" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.24.6.tgz#61275b485d7fd4e9d269c7cf04ec2873c9cc0f91" - integrity sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg== +undici-types@~8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-8.9.0.tgz#e240d97c8b5d85e5347ce73d25865c7906c1ec9f" + integrity sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg== unicorn-magic@^0.3.0: version "0.3.0" @@ -2699,10 +3109,10 @@ vfile@^6.0.0: "@types/unist" "^3.0.0" vfile-message "^4.0.0" -vite-plugin-checker@^0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.14.1.tgz#0fe694c6d90905c9da7658772fadab4823d7b881" - integrity sha512-Mv8oQc9XYBYf+XkP/riqqQCt8lBP6Iad75PZPho1lHRrpxQI0BwX2gwE10enn4f6Hgc+PvR1F7N38KARcaJtzw== +vite-plugin-checker@^0.14.5: + version "0.14.5" + resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.14.5.tgz#b809a65bbec0195d932bfee4bb3a49cdd2907640" + integrity sha512-c9lQ92eisUO+F7Fd93aelojmiOS+NQpPgQ1XR2LTQHox1/laZf4yAoQj+L3RA9Vgh10e2nFd9b8r2LLyYZsbpA== dependencies: "@babel/code-frame" "^7.29.0" chokidar "^5.0.0" @@ -2712,31 +3122,31 @@ vite-plugin-checker@^0.14.1: proper-lockfile "^4.1.2" tiny-invariant "^1.3.3" -"vite@^6.0.0 || ^7.0.0 || ^8.0.0", vite@^8.0.14: - version "8.0.14" - resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.14.tgz#da5d8d1f63dbd106385cbe9c211acbc7a7a5b192" - integrity sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw== +"vite@^6.0.0 || ^7.0.0 || ^8.0.0", vite@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-8.3.0.tgz#f9565cfd4879d58d28fa64d3c7aff3b372d2ccc8" + integrity sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ== dependencies: - lightningcss "^1.32.0" - picomatch "^4.0.4" - postcss "^8.5.15" - rolldown "1.0.2" - tinyglobby "^0.2.16" + lightningcss "^1.33.0" + picomatch "^4.0.7" + postcss "^8.5.28" + rolldown "~1.2.6" + tinyglobby "^0.2.17" optionalDependencies: fsevents "~2.3.3" -vitest@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.7.tgz#5ae483c0a901081bbf1428e07dafe80c36e62e6c" - integrity sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA== - dependencies: - "@vitest/expect" "4.1.7" - "@vitest/mocker" "4.1.7" - "@vitest/pretty-format" "4.1.7" - "@vitest/runner" "4.1.7" - "@vitest/snapshot" "4.1.7" - "@vitest/spy" "4.1.7" - "@vitest/utils" "4.1.7" +vitest@^4.1.11: + version "4.1.11" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.11.tgz#1653c1521ae917f960d9b21877797c47dfd8bf21" + integrity sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw== + dependencies: + "@vitest/expect" "4.1.11" + "@vitest/mocker" "4.1.11" + "@vitest/pretty-format" "4.1.11" + "@vitest/runner" "4.1.11" + "@vitest/snapshot" "4.1.11" + "@vitest/spy" "4.1.11" + "@vitest/utils" "4.1.11" es-module-lexer "^2.0.0" expect-type "^1.3.0" magic-string "^0.30.21" @@ -2776,10 +3186,10 @@ why-is-node-running@^2.3.0: siginfo "^2.0.0" stackback "0.0.2" -ws@^8.18.3: - version "8.19.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" - integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== +ws@^8.21.0: + version "8.21.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.21.3.tgz#660b4faddb6a3e575c86e078126919961f4de4fc" + integrity sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw== yaml@^1.10.0: version "1.10.3" diff --git a/scripts/ci/fulltest-cypress b/scripts/ci/fulltest-cypress index 8fb896967c..a43f420eb0 100755 --- a/scripts/ci/fulltest-cypress +++ b/scripts/ci/fulltest-cypress @@ -65,7 +65,8 @@ rm -rf "${LOCAL_RESOLVE}" printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}" # bring up all remaining containers, except cypress! -docker compose up -d --remove-orphans stepca squid +docker compose build examplesite +docker compose up -d --remove-orphans --no-build stepca squid examplesite docker compose pull db-mysql || true # ok to fail docker compose pull db-postgres || true # ok to fail docker compose pull authentik authentik-redis authentik-ldap || true # ok to fail diff --git a/scripts/wait-healthy b/scripts/wait-healthy index 503d6a908e..7ca017686d 100755 --- a/scripts/wait-healthy +++ b/scripts/wait-healthy @@ -19,7 +19,7 @@ echo -e "${BLUE}❯ ${CYAN}Waiting for healthy: ${YELLOW}${SERVICE}${RESET}" until [ "${HEALTHY}" = "healthy" ]; do echo -n "." sleep 1 - HEALTHY="$(docker inspect -f '{{.State.Health.Status}}' $SERVICE)" + HEALTHY="$(docker inspect -f '{{.State.Health.Status}}' "$SERVICE")" ((LOOPCOUNT++)) if [ "$LOOPCOUNT" == "$LIMIT" ]; then diff --git a/test/cypress/config/ci.mjs b/test/cypress/config/ci.mjs index ea203a89ee..86c0a80dfb 100644 --- a/test/cypress/config/ci.mjs +++ b/test/cypress/config/ci.mjs @@ -1,6 +1,8 @@ import { defineConfig } from 'cypress'; import pluginSetup from '../plugins/index.mjs'; +const adminPort = process.env.NPM_ADMIN_PORT ?? 81; + export default defineConfig({ allowCypressEnv: false, requestTimeout: 30000, @@ -19,6 +21,6 @@ export default defineConfig({ env: { swaggerBase: `{{baseUrl}}/api/schema?ts=${Date.now()}`, }, - baseUrl: "http://fullstack:81", + baseUrl: `http://fullstack:${adminPort}`, } }); diff --git a/test/cypress/e2e/api/AccessListLocations.cy.js b/test/cypress/e2e/api/AccessListLocations.cy.js new file mode 100644 index 0000000000..2ea2742ef8 --- /dev/null +++ b/test/cypress/e2e/api/AccessListLocations.cy.js @@ -0,0 +1,301 @@ +/// + +describe('Per-path Access Lists', () => { + const domain = 'website3.example.com'; + + const alpha = { + name: 'Path Alpha', + username: 'alpha-user', + password: 'alpha-pass', + }; + + const beta = { + name: 'Path Beta', + username: 'beta-user', + password: 'beta-pass', + }; + + let token; + let alphaListId; + let betaListId; + let hostId; + + /** + * Requests a path on the proxy host directly (bypassing squid) + * and yields the HTTP status code and response body + * + * @param {string} path + * @param {object} [creds] + * @param {string} creds.username + * @param {string} creds.password + */ + const request = (path, creds) => { + const auth = creds ? `-u '${creds.username}:${creds.password}'` : ''; + return cy.exec(`curl --noproxy '*' -s -w '\n%{http_code}' ${auth} http://${domain}${path}`) + .then((result) => { + expect(result.exitCode).to.eq(0); + const lines = result.stdout.trim().split('\n'); + const status = lines.pop(); + return { status: status, body: lines.join('\n') }; + }); + }; + + // nginx reloads are signalled and return immediately, so the old + // config can still be served for a moment after an API change. + // Retry until the expected response is seen. + const waitForResponse = (path, creds, check, description) => { + // Copy now, the callback runs later and creds may have been changed by then + const credsCopy = creds ? { ...creds } : null; + let last = null; + cy.waitUntil(() => request(path, credsCopy).then((res) => { + last = res; + return check(res); + }), { + timeout: 15000, + interval: 500, + errorMsg: () => `${path} did not return ${description}, last status: ${last?.status}`, + }); + }; + + const expectStatus = (path, creds, status) => { + waitForResponse(path, creds, (res) => res.status === status, status); + }; + + // Also checks the body so we know the page came from examplesite + // and not the NPM default site + const expectPage = (path, creds, text) => { + waitForResponse(path, creds, (res) => res.status === '200' && res.body.includes(text), `200 with "${text}"`); + }; + + const createAccessList = (list) => { + return cy.task('backendApiPost', { + token: token, + path: '/api/nginx/access-lists', + data: { + name: list.name, + satisfy_any: false, + pass_auth: false, + items: [ + { + username: list.username, + password: list.password, + } + ], + clients: [], + } + }).then((data) => { + cy.validateSwaggerSchema('post', 201, '/nginx/access-lists', data); + expect(data).to.have.property('id'); + expect(data.id).to.be.greaterThan(0); + return cy.wrap(data.id); + }); + }; + + const location = (path, accessListId) => { + return { + path: path, + forward_scheme: 'http', + forward_host: 'examplesite', + forward_port: 80, + access_list_id: accessListId, + }; + }; + + before(() => { + cy.resetUsers(); + cy.getToken().then((tok) => { + token = tok; + }); + }); + + it('Should be able to create multiple access lists with credentials', () => { + createAccessList(alpha).then((id) => { + alphaListId = id; + }); + createAccessList(beta).then((id) => { + betaListId = id; + expect(betaListId).to.not.equal(alphaListId); + }); + }); + + it('Should be able to create a proxy host with a different access list per location', () => { + cy.task('backendApiPost', { + token: token, + path: '/api/nginx/proxy-hosts', + data: { + domain_names: [domain], + forward_scheme: 'http', + forward_host: 'examplesite', + forward_port: 80, + access_list_id: 0, + certificate_id: 0, + meta: { + dns_challenge: false + }, + advanced_config: '', + locations: [ + location('/dashboard', alphaListId), + location('/profile', betaListId), + ], + block_exploits: false, + caching_enabled: false, + allow_websocket_upgrade: false, + http2_support: false, + hsts_enabled: false, + hsts_subdomains: false, + ssl_forced: false + } + }).then((data) => { + cy.validateSwaggerSchema('post', 201, '/nginx/proxy-hosts', data); + expect(data).to.have.property('id'); + expect(data.id).to.be.greaterThan(0); + hostId = data.id; + expect(data).to.have.property('enabled', true); + expect(data).to.have.property('access_list_id', 0); + expect(data.locations).to.have.length(2); + expect(data.locations[0]).to.have.property('access_list_id', alphaListId); + expect(data.locations[1]).to.have.property('access_list_id', betaListId); + }); + }); + + it('Should persist the location access lists on the proxy host', () => { + cy.task('backendApiGet', { + token: token, + path: `/api/nginx/proxy-hosts/${hostId}`, + }).then((data) => { + cy.validateSwaggerSchema('get', 200, '/nginx/proxy-hosts/{hostID}', data); + expect(data.locations[0]).to.have.property('path', '/dashboard'); + expect(data.locations[0]).to.have.property('access_list_id', alphaListId); + expect(data.locations[1]).to.have.property('path', '/profile'); + expect(data.locations[1]).to.have.property('access_list_id', betaListId); + }); + }); + + it('Should not require auth for the host root', () => { + expectPage('/', null, 'this is the index page'); + }); + + it('Should only accept the alpha credentials on /dashboard', () => { + expectStatus('/dashboard', null, '401'); + expectStatus('/dashboard', beta, '401'); + expectPage('/dashboard', alpha, 'this is the dashboard page'); + }); + + it('Should only accept the beta credentials on /profile', () => { + expectStatus('/profile', null, '401'); + expectStatus('/profile', alpha, '401'); + expectPage('/profile', beta, 'this is the profile page'); + }); + + it('Should apply access list credential changes to locations using it', () => { + const newPassword = 'alpha-pass-changed'; + + cy.task('backendApiPut', { + token: token, + path: `/api/nginx/access-lists/${alphaListId}`, + data: { + name: alpha.name, + satisfy_any: false, + pass_auth: false, + items: [ + { + username: alpha.username, + password: newPassword, + } + ], + clients: [], + } + }).then((data) => { + cy.validateSwaggerSchema('put', 200, '/nginx/access-lists/{listID}', data); + expect(data).to.have.property('id', alphaListId); + }); + + expectStatus('/dashboard', alpha, '401'); + expectPage('/dashboard', { username: alpha.username, password: newPassword }, 'this is the dashboard page'); + alpha.password = newPassword; + + // Other locations are unaffected + expectStatus('/profile', null, '401'); + expectPage('/profile', beta, 'this is the profile page'); + }); + + it('Should inherit the host access list on locations without their own', () => { + // Host uses beta, /dashboard overrides with alpha, /missing has none and should inherit beta + cy.task('backendApiPut', { + token: token, + path: `/api/nginx/proxy-hosts/${hostId}`, + data: { + access_list_id: betaListId, + locations: [ + location('/dashboard', alphaListId), + location('/profile', betaListId), + location('/missing', 0), + ], + } + }).then((data) => { + // No swagger validation here: with a host access list set, the expanded + // access_list in the response has no proxy_host_count, which the schema requires + expect(data).to.have.property('access_list_id', betaListId); + expect(data.locations[2]).to.have.property('access_list_id', 0); + }); + + expectStatus('/', null, '401'); + expectStatus('/', alpha, '401'); + expectPage('/', beta, 'this is the index page'); + + // examplesite returns 404 for this path, once past the access list + expectStatus('/missing', null, '401'); + expectStatus('/missing', alpha, '401'); + expectStatus('/missing', beta, '404'); + + expectStatus('/dashboard', beta, '401'); + expectPage('/dashboard', alpha, 'this is the dashboard page'); + }); + + it('Should remove a deleted access list from the host and locations using it', () => { + cy.task('backendApiDelete', { + token: token, + path: `/api/nginx/access-lists/${betaListId}`, + }).then((data) => { + cy.validateSwaggerSchema('delete', 200, '/nginx/access-lists/{listID}', data); + expect(data).to.be.equal(true); + }); + + cy.task('backendApiGet', { + token: token, + path: `/api/nginx/proxy-hosts/${hostId}`, + }).then((data) => { + expect(data).to.have.property('access_list_id', 0); + expect(data.locations[0]).to.have.property('access_list_id', alphaListId); + expect(data.locations[1]).to.have.property('access_list_id', 0); + expect(data.locations[2]).to.have.property('access_list_id', 0); + }); + + expectPage('/', null, 'this is the index page'); + expectPage('/profile', null, 'this is the profile page'); + expectStatus('/missing', null, '404'); + + // Remaining location access list must still be enforced + expectStatus('/dashboard', null, '401'); + expectPage('/dashboard', alpha, 'this is the dashboard page'); + }); + + it('Should be able to delete the proxy host and remaining access list', () => { + cy.task('backendApiDelete', { + token: token, + path: `/api/nginx/proxy-hosts/${hostId}`, + }).then((data) => { + cy.validateSwaggerSchema('delete', 200, '/nginx/proxy-hosts/{hostID}', data); + expect(data).to.be.equal(true); + }); + + cy.task('backendApiDelete', { + token: token, + path: `/api/nginx/access-lists/${alphaListId}`, + }).then((data) => { + cy.validateSwaggerSchema('delete', 200, '/nginx/access-lists/{listID}', data); + expect(data).to.be.equal(true); + }); + }); + +}); diff --git a/test/cypress/e2e/api/Users.cy.js b/test/cypress/e2e/api/Users.cy.js index 044dcdee9c..41808d0a63 100644 --- a/test/cypress/e2e/api/Users.cy.js +++ b/test/cypress/e2e/api/Users.cy.js @@ -31,6 +31,49 @@ describe('Users endpoints', () => { }); }); + it('Should reject a token that was issued before the password changed', () => { + // The token carries whole seconds, so it has to predate the change by one. + cy.wait(1100); + + cy.task('backendApiPut', { + token: token, + path: '/api/users/me/auth', + data: { + type: 'password', + current: 'changeme', + secret: 'changeme2' + } + }).then(() => { + cy.task('backendApiGet', { + token: token, + path: '/api/users/me', + returnOnError: true + }).then((data) => { + expect(data).to.have.property('error'); + expect(data.error).to.have.property('code'); + expect(data.error.code).to.equal(401); + }); + + // Put the password back, the rest of the suite shares this user, and take a + // token minted after the change: restoring it invalidates the one that made it. + cy.getToken(null, {secret: 'changeme2'}).then((tempToken) => { + cy.task('backendApiPut', { + token: tempToken, + path: '/api/users/me/auth', + data: { + type: 'password', + current: 'changeme2', + secret: 'changeme' + } + }).then(() => { + cy.getToken().then((freshToken) => { + token = freshToken; + }); + }); + }); + }); + }); + it('Should be able to update yourself', () => { cy.task('backendApiPut', { token: token, diff --git a/test/docker/Dockerfile.website b/test/docker/Dockerfile.website new file mode 100644 index 0000000000..311272d8c4 --- /dev/null +++ b/test/docker/Dockerfile.website @@ -0,0 +1,6 @@ +FROM nginx:stable + +RUN rm -rf /etc/nginx/conf.d +COPY nginx /etc/nginx +COPY www /www +RUN chown -R nginx:nginx /www diff --git a/test/docker/nginx/conf.d/website123.conf b/test/docker/nginx/conf.d/website123.conf new file mode 100644 index 0000000000..656f3ade42 --- /dev/null +++ b/test/docker/nginx/conf.d/website123.conf @@ -0,0 +1,29 @@ +server { + listen 80; + server_name website1.example.com website2.example.com website3.example.com; + root /www; + index index.html; + + # redirect requests for .html URLs to their extensionless form + if ($request_uri ~ ^/index\.html(\?.*)?$) { + return 301 /$1; + } + if ($request_uri ~ ^/(.+)\.html(\?.*)?$) { + return 301 /$1$2; + } + + location / { + try_files $uri $uri.html $uri/ =404; + } + + error_page 404 /404.html; + location = /404.html { + internal; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + location ~ /\.ht { + deny all; + } +} diff --git a/test/docker/nginx/nginx.conf b/test/docker/nginx/nginx.conf new file mode 100644 index 0000000000..82366ca042 --- /dev/null +++ b/test/docker/nginx/nginx.conf @@ -0,0 +1,30 @@ +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + server_tokens off; + + log_format custom_combined '$remote_addr - $remote_user [$time_local] "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; + + access_log /var/log/nginx/access.log custom_combined; + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + gzip on; + + set_real_ip_from 10.0.0.0/8; + set_real_ip_from 172.16.0.0/12; # Includes Docker subnet + set_real_ip_from 192.168.0.0/16; + + include include/*.conf; + include conf.d/*.conf; + include /sites/*/nginx.conf; +} diff --git a/test/docker/www/404.html b/test/docker/www/404.html new file mode 100644 index 0000000000..389d3cafb1 --- /dev/null +++ b/test/docker/www/404.html @@ -0,0 +1,9 @@ + + + 404 + + + 404 not found + + + diff --git a/test/docker/www/dashboard.html b/test/docker/www/dashboard.html new file mode 100644 index 0000000000..d26099e8f9 --- /dev/null +++ b/test/docker/www/dashboard.html @@ -0,0 +1,9 @@ + + + Dashboard + + + this is the dashboard page + + + diff --git a/test/docker/www/index.html b/test/docker/www/index.html new file mode 100644 index 0000000000..3a190926cb --- /dev/null +++ b/test/docker/www/index.html @@ -0,0 +1,9 @@ + + + Index + + + this is the index page + + + diff --git a/test/docker/www/profile.html b/test/docker/www/profile.html new file mode 100644 index 0000000000..1058ca4a15 --- /dev/null +++ b/test/docker/www/profile.html @@ -0,0 +1,9 @@ + + + Profile + + + this is the profile page + + + diff --git a/test/package.json b/test/package.json index c1a79d9b88..84062e8926 100644 --- a/test/package.json +++ b/test/package.json @@ -4,21 +4,21 @@ "description": "", "main": "index.js", "dependencies": { - "@cypress/grep": "^6.0.0", + "@cypress/grep": "^7.0.0", "@jc21/cypress-swagger-validation": "^0.3.2", "@quobix/vacuum": "^0.26.4", - "axios": "^1.16.0", + "axios": "^1.19.0", "chalk": "^5.6.2", - "cypress": "^15.15.0", + "cypress": "^16.0.0", "cypress-multi-reporters": "^2.0.5", "cypress-wait-until": "^3.0.2", - "eslint": "^10.3.0", + "eslint": "^10.9.1", "eslint-plugin-align-assignments": "^1.1.2", - "eslint-plugin-chai-friendly": "^1.2.0", - "eslint-plugin-cypress": "^6.4.1", - "form-data": "^4.0.5", + "eslint-plugin-chai-friendly": "^1.2.1", + "eslint-plugin-cypress": "^7.0.1", + "form-data": "^4.0.6", "lodash": "^4.18.1", - "mocha": "^11.7.5", + "mocha": "^12.0.0", "mocha-junit-reporter": "^2.2.1" }, "scripts": { diff --git a/test/yarn.lock b/test/yarn.lock index 0f41aea86c..4eb1a544f7 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -80,10 +80,10 @@ "@babel/helper-string-parser" "^7.29.7" "@babel/helper-validator-identifier" "^7.29.7" -"@cypress/grep@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@cypress/grep/-/grep-6.0.0.tgz#fcc5f42d0086464e2752c4d84ac563c3cd21eb77" - integrity sha512-n3PCeqt8OwmLFz310igbRUm3qDE5WJgM9LW+2ejdULfMu2Sudqg3UX8koC8/JU/+ZcJ5UbaQAap1Nbi0QvzXwA== +"@cypress/grep@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@cypress/grep/-/grep-7.0.0.tgz#2cdc92a395017947dc18fe3623fa7334631887e1" + integrity sha512-pk1EJaIzt8xQZYA47xvwA2mA+ajGd73mDSIdYeAxYRuyifLVZGhTf1FpuTktjPYGarkdLjWKzDSijGfJnn6lEA== dependencies: debug "^4.3.4" find-test-names "^1.28.18" @@ -141,10 +141,10 @@ debug "^4.3.1" minimatch "^10.2.4" -"@eslint/config-helpers@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.6.0.tgz#ef9a36881d39dfd5dbeac22b0da997fabfb08b03" - integrity sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA== +"@eslint/config-helpers@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.7.0.tgz#09ee4aa07b73f059ec2d4c74bf4b2ff02b322377" + integrity sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw== dependencies: "@eslint/core" "^1.2.1" @@ -160,27 +160,35 @@ resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-3.0.5.tgz#88e9bf4d11d2b19c082e78ebe7ce88724a5eb091" integrity sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw== -"@eslint/plugin-kit@^0.7.1": - version "0.7.1" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz#c4125fd015eceeb09b793109fdbcd4dd0a02d346" - integrity sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ== +"@eslint/plugin-kit@^0.7.2": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz#4b0962f3f2c7ce8bc98b3ecfe34525c09d2cb729" + integrity sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A== dependencies: "@eslint/core" "^1.2.1" levn "^0.4.1" -"@humanfs/core@^0.19.1": - version "0.19.1" - resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" - integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== +"@humanfs/core@^0.19.2": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.2.tgz#a8272ca03b2acf492670222b2320b6c421bfde60" + integrity sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA== + dependencies: + "@humanfs/types" "^0.15.0" "@humanfs/node@^0.16.6": - version "0.16.7" - resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" - integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + version "0.16.8" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.8.tgz#8f800cccc13f4f8cd3116e2d9c0a94939da3e3ed" + integrity sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ== dependencies: - "@humanfs/core" "^0.19.1" + "@humanfs/core" "^0.19.2" + "@humanfs/types" "^0.15.0" "@humanwhocodes/retry" "^0.4.0" +"@humanfs/types@^0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@humanfs/types/-/types-0.15.0.tgz#f2a09f62012390b2bff3fc6fb248ddec8c09a090" + integrity sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q== + "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" @@ -191,18 +199,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - "@isaacs/fs-minipass@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" @@ -252,11 +248,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - "@quobix/vacuum@^0.26.4": version "0.26.8" resolved "https://registry.yarnpkg.com/@quobix/vacuum/-/vacuum-0.26.8.tgz#1a912c10655ab59c5af7179ff0cbe76609fb44de" @@ -369,27 +360,27 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^6.0.1, ansi-regex@^6.2.2: +ansi-regex@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -ansi-styles@^6.1.0, ansi-styles@^6.2.1, ansi-styles@^6.2.3: +ansi-styles@^6.2.1, ansi-styles@^6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== -arch@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== +arch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-3.0.0.tgz#a44e7077da4615fc5f1e3da21fbfc201d2c1817c" + integrity sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q== argparse@^2.0.1: version "2.0.1" @@ -433,21 +424,16 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axios@^1.16.0, axios@^1.7.7: - version "1.16.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.16.1.tgz#517e29291d19d6e8cf919ff264f4fe157261ba12" - integrity sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A== +axios@^1.19.0, axios@^1.7.7: + version "1.20.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.20.0.tgz#515513445aa60e71d04b6521ca6210829ccb4786" + integrity sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg== dependencies: follow-redirects "^1.16.0" - form-data "^4.0.5" + form-data "^4.0.6" https-proxy-agent "^5.0.1" proxy-from-env "^2.1.0" -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - balanced-match@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.3.tgz#6337a2f23e0604a30481423432f99eac603599f9" @@ -475,17 +461,10 @@ bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -brace-expansion@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" - integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== - dependencies: - balanced-match "^1.0.0" - -brace-expansion@^5.0.5: - version "5.0.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.6.tgz#ec68fe0a641a29d8711579caf641d05bae1f2285" - integrity sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g== +brace-expansion@^5.0.8: + version "5.0.9" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.9.tgz#7c72438809b5fa5babf54199a1f1c281a6984fcf" + integrity sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg== dependencies: balanced-match "^4.0.2" @@ -540,11 +519,6 @@ call-me-maybe@^1.0.2: resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== -camelcase@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -568,18 +542,26 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== -chokidar@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== +chokidar@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-5.0.0.tgz#949c126a9238a80792be9a0265934f098af369a5" + integrity sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw== dependencies: - readdirp "^4.0.1" + readdirp "^5.0.0" chownr@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== +chrome-remote-interface@0.33.3: + version "0.33.3" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.33.3.tgz#d8b4339f487b460a9461af7355bda98054e8e1a4" + integrity sha512-zNnn0prUL86Teru6UCAZ1yU1XeXljHl3gj7OrfPcarEfU62OUU4IujDPdTDW3dAWwRqN3ZMG/Chhkh2gPL/wiw== + dependencies: + commander "2.11.x" + ws "^7.2.0" + ci-info@^4.1.0: version "4.4.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.4.0.tgz#7d54eff9f54b45b62401c26032696eb59c8bd18c" @@ -609,15 +591,6 @@ cli-truncate@^5.0.0: slice-ansi "^8.0.0" string-width "^8.2.0" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -647,6 +620,11 @@ combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@2.11.x: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== + commander@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" @@ -690,27 +668,28 @@ cypress-wait-until@^3.0.2: resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-3.0.2.tgz#c90dddfa4c46a2c422f5b91d486531c560bae46e" integrity sha512-iemies796dD5CgjG5kV0MnpEmKSH+s7O83ZoJLVzuVbZmm4lheMsZqAVT73hlMx4QlkwhxbyUzhOBUOZwoOe0w== -cypress@^15.15.0: - version "15.16.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-15.16.0.tgz#482f77e6f85aee98b94a5ad844d36f69dc212c28" - integrity sha512-fy0M0c9xDLEp4v9y7LLKFeAQhIdDsobxDSKpD3JcZpqQefjy9TSzEyVV3HA0zu7hUi0bGHlSYlI7ASub8wgR9A== +cypress@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-16.0.0.tgz#22afcb0dbc9dda87188b05b0d7ac058215b8c35e" + integrity sha512-/H3zsayGwIGboFIiLWaXxy6ADmCdWy5QjjDBZgslCvjIgYAf1DkZerwAM7wXMPSpfpQ4w+lGjFlmwneRBpg27g== dependencies: "@cypress/request" "^4.0.0" "@cypress/xvfb" "^1.2.4" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" "@types/tmp" "^0.2.3" - arch "^2.2.0" + arch "^3.0.0" blob-util "^2.0.2" bluebird "^3.7.2" buffer "^5.7.1" cachedir "^2.4.0" chalk "^4.1.0" + chrome-remote-interface "0.33.3" ci-info "^4.1.0" cli-table3 "0.6.1" commander "^6.2.1" common-tags "^1.8.0" - dayjs "^1.10.4" + dayjs "^1.11.23" debug "^4.3.4" eventemitter2 "6.4.7" execa "4.1.0" @@ -731,7 +710,6 @@ cypress@^15.15.0: systeminformation "^5.31.1" tmp "~0.2.4" tree-kill "1.2.2" - tslib "1.14.1" untildify "^4.0.0" yauzl "^3.3.1" @@ -747,10 +725,10 @@ data-uri-to-buffer@^4.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== -dayjs@^1.10.4: - version "1.11.19" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" - integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== +dayjs@^1.11.23: + version "1.11.23" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.23.tgz#b0a363506dde5f36cf5075e42ebe8115165a8c79" + integrity sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ== debug@4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0: version "4.4.3" @@ -766,11 +744,6 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -781,10 +754,10 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -diff@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a" - integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw== +diff@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-9.0.0.tgz#297c31cd7c280f13dfe335791ec2063bd4a73a6f" + integrity sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw== dir-glob@^3.0.1: version "3.0.1" @@ -802,11 +775,6 @@ dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -825,11 +793,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - end-of-stream@^1.1.0: version "1.4.5" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" @@ -869,11 +832,6 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" -escalade@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -895,17 +853,17 @@ eslint-plugin-align-assignments@^1.1.2: resolved "https://registry.yarnpkg.com/eslint-plugin-align-assignments/-/eslint-plugin-align-assignments-1.1.2.tgz#83e1a8a826d4adf29e82b52d0bb39c88b301b576" integrity sha512-I1ZJgk9EjHfGVU9M2Ex8UkVkkjLL5Y9BS6VNnQHq79eHj2H4/Cgxf36lQSUTLgm2ntB03A2NtF+zg9fyi5vChg== -eslint-plugin-chai-friendly@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-1.2.0.tgz#2a54b481bcbc26ab5a581b2b7e7c304465837c15" - integrity sha512-um2pBb4ZXNCoTRPRAWiUaXeIaw1dRaPOEZ+G/qcZqfyTdkCXXwOBctnfnbIRbZiQf4AXl3ImV1grt423SlK+mg== +eslint-plugin-chai-friendly@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-1.2.1.tgz#141392762aa8626ac3d25780a502e625ce74922b" + integrity sha512-mV3EOJLDr8+L+LS8uCkP711fnNHz+4PsmPyz18xwkvjJwfLRlnx0Eu6CFnb5B+dW5ahoav2jVer2KFYsmIuv3A== -eslint-plugin-cypress@^6.4.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-6.4.1.tgz#2aa64e5a2dcc56b8b916fdf8398a81b31a61c462" - integrity sha512-8mnfR3q0Lr41Fu9SYZGeZ5nbSBgtS44+bbtSs7k0KvfoQ2pPmK43IvaTP6FGTfwBTN6S7w027CpqjrLAd65AYA== +eslint-plugin-cypress@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-7.0.1.tgz#eb80500478533204ad5ebd2e49944224b0e47941" + integrity sha512-Jn2sV9rt8iiUYZY+iGY8fvV8iseJ6Tl1jngnLeSRyuHvYgxEbDUUFwNhwj1cr9gI4xCzTDh4mgXJ3YY7+dEMVg== dependencies: - globals "^17.6.0" + globals "^17.11.0" eslint-scope@^9.1.2: version "9.1.2" @@ -927,17 +885,17 @@ eslint-visitor-keys@^5.0.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be" integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== -eslint@^10.3.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.4.0.tgz#d86b6c405de0f19f3318c47139b8cb6771b3f592" - integrity sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ== +eslint@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.9.1.tgz#409da5c41a5536d5a849f8555a18ca7ef1eb963b" + integrity sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A== dependencies: "@eslint-community/eslint-utils" "^4.8.0" "@eslint-community/regexpp" "^4.12.2" "@eslint/config-array" "^0.23.5" - "@eslint/config-helpers" "^0.6.0" + "@eslint/config-helpers" "^0.7.0" "@eslint/core" "^1.2.1" - "@eslint/plugin-kit" "^0.7.1" + "@eslint/plugin-kit" "^0.7.2" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" "@humanwhocodes/retry" "^0.4.2" @@ -959,7 +917,7 @@ eslint@^10.3.0: imurmurhash "^0.1.4" is-glob "^4.0.0" json-stable-stringify-without-jsonify "^1.0.1" - minimatch "^10.2.4" + minimatch "^10.2.5" natural-compare "^1.4.0" optionator "^0.9.3" @@ -1080,9 +1038,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-uri@^3.0.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.2.tgz#8af3d4fc9d3e71b11572cc2673b514a7d1a8c8ec" - integrity sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ== + version "3.1.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.6.tgz#bfdd308ef763f835fed059f3c6c925f708e33e3a" + integrity sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q== fastq@^1.6.0: version "1.20.1" @@ -1146,11 +1104,6 @@ flat-cache@^4.0.0: flatted "^3.2.9" keyv "^4.5.4" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - flatted@^3.2.9: version "3.4.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726" @@ -1161,29 +1114,21 @@ follow-redirects@^1.16.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.16.0.tgz#28474a159d3b9d11ef62050a14ed60e4df6d61bc" integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw== -foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== - dependencies: - cross-spawn "^7.0.6" - signal-exit "^4.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -form-data@^4.0.5, form-data@~4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" - integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== +form-data@^4.0.6, form-data@~4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.6.tgz#28e864e1b786dbebb68db1f452f9635278665827" + integrity sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" es-set-tostringtag "^2.1.0" - hasown "^2.0.2" - mime-types "^2.1.12" + hasown "^2.0.4" + mime-types "^2.1.35" formdata-polyfill@^4.0.10: version "4.0.10" @@ -1207,11 +1152,6 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1, get-east-asian-width@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz#216900f91df11a8b2c198c3e1d93d6c035a776b9" @@ -1269,17 +1209,14 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.4.5: - version "10.5.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" - integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== +glob@^13.0.0: + version "13.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" + integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" + minimatch "^10.2.2" + minipass "^7.1.3" + path-scurry "^2.0.2" global-dirs@^3.0.0: version "3.0.1" @@ -1288,10 +1225,10 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" -globals@^17.6.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-17.6.0.tgz#0f0be018d5cca8690e6375ead1f65c4bb96191fc" - integrity sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA== +globals@^17.11.0: + version "17.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-17.11.0.tgz#d643485bb30220d7751e511cf4f68c73d3870d87" + integrity sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw== globby@^11.0.4: version "11.1.0" @@ -1347,10 +1284,12 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" -he@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hasown@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== + dependencies: + function-bind "^1.1.2" http-signature@~1.4.0: version "1.4.0" @@ -1449,11 +1388,6 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -1479,19 +1413,17 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== +js-yaml@^4.1.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.1.tgz#01216c001d67f48e2cd560d708c7af21090a3848" + integrity sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ== dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" + argparse "^2.0.1" -js-yaml@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" - integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== +js-yaml@^5.0.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-5.4.1.tgz#4629d91d4b4551f300435f0e4127899710f816fb" + integrity sha512-28R/k+NAjeuf7+CKlTxWZVExJGwVVLwY06DgEnOMz2gEpfNkDcD7QvyiVPT0xy0XXhU8vHsd4Ot42OOPdJG7dQ== dependencies: argparse "^2.0.1" @@ -1602,7 +1534,7 @@ lodash@^4.17.21, lodash@^4.17.23, lodash@^4.18.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c" integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q== -log-symbols@^4.0.0, log-symbols@^4.1.0: +log-symbols@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -1621,10 +1553,10 @@ log-update@^6.1.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.0.0: + version "11.5.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.2.tgz#00e16665c90c620fba14a3c368732a976493f760" + integrity sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g== math-intrinsics@^1.1.0: version "1.1.0" @@ -1663,7 +1595,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19: +mime-types@^2.1.35, mime-types@~2.1.19: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -1680,26 +1612,19 @@ mimic-function@^5.0.0: resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== -minimatch@^10.2.4: - version "10.2.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" - integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== +minimatch@^10.2.2, minimatch@^10.2.4, minimatch@^10.2.5: + version "10.2.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef" + integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A== dependencies: - brace-expansion "^5.0.5" - -minimatch@^9.0.4, minimatch@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" + brace-expansion "^5.0.8" minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: +minipass@^7.0.4, minipass@^7.1.2, minipass@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== @@ -1727,32 +1652,27 @@ mocha-junit-reporter@^2.2.1: strip-ansi "^6.0.1" xml "^1.0.1" -mocha@^11.7.5: - version "11.7.6" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.7.6.tgz#ebbe22989d04cbb9424a36307320476624c41a33" - integrity sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA== +mocha@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-12.0.0.tgz#6284d68e66fac4597e8411b0fd62ab4c6717023c" + integrity sha512-NYNh5IFt6WYqm9bi4601m7vix8MZdXC0DwS4gY6WhXO2RgJWhivhISVmq1oklCif18OSI9l+vx5Mdm5oh1XGiQ== dependencies: browser-stdout "^1.3.1" - chokidar "^4.0.1" + chokidar "^5.0.0" debug "^4.3.5" - diff "^7.0.0" - escape-string-regexp "^4.0.0" + diff "^9.0.0" find-up "^5.0.0" - glob "^10.4.5" - he "^1.2.0" + glob "^13.0.0" is-path-inside "^3.0.3" - js-yaml "^4.1.0" - log-symbols "^4.1.0" - minimatch "^9.0.5" + is-unicode-supported "^0.1.0" + js-yaml "^5.0.0" + minimatch "^10.2.2" ms "^2.1.3" picocolors "^1.1.1" - serialize-javascript "^6.0.2" - strip-json-comments "^3.1.1" + serialize-javascript "^7.0.2" + strip-json-comments "^5.0.3" supports-color "^8.1.1" - workerpool "^9.2.0" - yargs "^17.7.2" - yargs-parser "^21.1.1" - yargs-unparser "^2.0.0" + workerpool "^10.0.0" ms@^2.1.1, ms@^2.1.3: version "2.1.3" @@ -1847,11 +1767,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -1862,13 +1777,13 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== +path-scurry@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" + integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + lru-cache "^11.0.0" + minipass "^7.1.2" path-type@^4.0.0: version "4.0.0" @@ -1955,17 +1870,10 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -readdirp@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== +readdirp@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-5.1.1.tgz#520bca06f9d1ae1b96cc0800dbe84b983d19422c" + integrity sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA== request-progress@^3.0.0: version "3.0.0" @@ -1974,11 +1882,6 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -2009,7 +1912,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -2024,12 +1927,10 @@ semver@^7.6.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== -serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" +serialize-javascript@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-7.1.1.tgz#c3b0a7ac13df6cf2fcda71cbb142ba9392a710b9" + integrity sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ== shebang-command@^2.0.0: version "2.0.0" @@ -2088,7 +1989,7 @@ signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1, signal-exit@^4.1.0: +signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -2146,16 +2047,7 @@ static-eval@2.1.1: dependencies: escodegen "^2.1.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2164,15 +2056,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - string-width@^7.0.0: version "7.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" @@ -2190,27 +2073,13 @@ string-width@^8.2.0: get-east-asian-width "^1.5.0" strip-ansi "^7.1.2" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" - integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== - dependencies: - ansi-regex "^6.0.1" - strip-ansi@^7.1.0, strip-ansi@^7.1.2: version "7.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.2.0.tgz#d22a269522836a627af8d04b5c3fd2c7fa3e32e3" @@ -2223,10 +2092,10 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" + integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== supports-color@^7.1.0: version "7.2.0" @@ -2243,14 +2112,14 @@ supports-color@^8.1.1: has-flag "^4.0.0" systeminformation@^5.31.1: - version "5.31.6" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.31.6.tgz#2da4979a7262974fd068a3a306ded30aed6127c0" - integrity sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA== + version "5.31.17" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.31.17.tgz#60bd1cdaeb34212b5ad2410608ee47d41d2d8560" + integrity sha512-TvFA9iwDWlMjqZVlKIJ0Cy+Zgm9ttlMx0SMRwJDMNKyhlEKWBMb3+WRwDi/3dvHdWbexpos4Osp4U49p5WjB5g== tar@^7.5.13: - version "7.5.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.15.tgz#afe6d1316cddf614a566e3813e42fe01aed46fee" - integrity sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ== + version "7.5.22" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.22.tgz#a696f998136e71487dc3f869a85bba2c67971ba9" + integrity sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA== dependencies: "@isaacs/fs-minipass" "^4.0.0" chownr "^3.0.0" @@ -2284,9 +2153,9 @@ tldts@^6.1.32: tldts-core "^6.1.86" tmp@~0.2.4: - version "0.2.5" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" - integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== + version "0.2.7" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.7.tgz#26f4db11d1601ce8012dcb8a798ece1c06a99059" + integrity sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw== to-regex-range@^5.0.1: version "5.0.1" @@ -2307,11 +2176,6 @@ tree-kill@1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -tslib@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -2384,37 +2248,10 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -workerpool@^9.2.0: - version "9.3.4" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" - integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg== - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" +workerpool@^10.0.0: + version "10.0.3" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-10.0.3.tgz#e9914112d0169a974fc1b4c2fda00388bbd70b61" + integrity sha512-6z2Iis68Wqth93/G/wJP9u+R3O+d2XTlgWChGCwuT1qLbBsOYueGRZuJ++v3mtDP5KjYdy+WzvWC+VWETSVXJA== wrap-ansi@^9.0.0: version "9.0.2" @@ -2430,49 +2267,21 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@^7.2.0: + version "7.5.13" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.13.tgz#12aa507eaca76c295c278b1aebf4698ab2c1845f" + integrity sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA== + xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - yallist@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs-unparser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - yauzl@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-3.3.1.tgz#b0de68ae3a862715e130849679a4236f54dba45f"