diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 34e07fec7..83b6b01f3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -33,6 +33,7 @@ body: options: # The below comment is used to insert a new version with on-release.yml #NEXT_VERSION# + - 1.67.0 - 1.66.1 - 1.66.0 - 1.65.0 diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index 98f9357db..359ca09d7 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -66,7 +66,7 @@ jobs: - uses: actions/setup-node@v6 if: env.SKIP_RELEASE == 'false' with: - node-version: 24.16.0 + node-version: 24.17.0 package-manager-cache: false - run: npm i -g pnpm if: env.SKIP_RELEASE == 'false' diff --git a/.github/workflows/deployment-weekly-release.yml b/.github/workflows/deployment-weekly-release.yml index 8cb117b8c..7c5c8d21d 100644 --- a/.github/workflows/deployment-weekly-release.yml +++ b/.github/workflows/deployment-weekly-release.yml @@ -3,6 +3,7 @@ name: "[Deployment] Automatic Weekly Release" on: schedule: - cron: "0 19 * * 5" # https://crontab.guru/#0_19_*_*_5 + timezone: Europe/Zurich workflow_dispatch: inputs: send-notifications: diff --git a/.mise.toml b/.mise.toml index 81a94b19f..0b18e941c 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,2 +1,2 @@ [tools] -node = "24.16.0" +node = "24.17.0" diff --git a/.nvmrc b/.nvmrc index b832e4001..1dd37d537 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24.16.0 +24.17.0 diff --git a/CODEOWNERS b/CODEOWNERS index b798cfada..b3e2214ac 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,6 +1,11 @@ # ── CODEOWNERS ─────────────────────────────────────── * @homarr-labs/maintainers +# Specific features / integrations +# Glueten +apps/docs/docs/integrations/glueten @Lok3sh-kumar +packages/integrations/src/gluetun @Lok3sh-kumar + # Exempt Renovate‑managed files (no owners) package.json **/package.json diff --git a/Dockerfile b/Dockerfile index fd852fd9e..d50756e39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:24.16.0-alpine AS base +FROM node:24.17.0-alpine AS base FROM base AS builder RUN apk add --no-cache libc6-compat @@ -20,6 +20,17 @@ ARG DISABLE_REDIS_LOGS='true' RUN corepack enable pnpm && pnpm build +# The standalone output tracing omits server chunk source maps (.next/server/**/*.map), which is +# where production Node stack frames point. Copy the .map files into the standalone tree (preserving +# directory structure) so the existing standalone COPY ships them, keeping traces readable. +# See https://github.com/homarr-labs/homarr/issues/5891 +RUN cd apps/nextjs/.next/server && \ + find . -name '*.map' | while IFS= read -r map; do \ + dest="../standalone/apps/nextjs/.next/server/$map"; \ + mkdir -p "$(dirname "$dest")"; \ + cp "$map" "$dest"; \ + done + FROM base AS runner WORKDIR /app @@ -64,6 +75,9 @@ ENV DB_DRIVER='better-sqlite3' ENV AUTH_PROVIDERS='credentials' ENV REDIS_IS_EXTERNAL='false' ENV NODE_ENV='production' +# Tell Node to symbolicate stack traces using the shipped .map files so production logs +# show original source locations instead of minified frames, see https://github.com/homarr-labs/homarr/issues/5891 +ENV NODE_OPTIONS='--enable-source-maps' ENTRYPOINT [ "/app/entrypoint.sh" ] CMD ["sh", "run.sh"] diff --git a/apps/docs/docs/integrations/gluetun/index.mdx b/apps/docs/docs/integrations/gluetun/index.mdx new file mode 100644 index 000000000..7c936fc1f --- /dev/null +++ b/apps/docs/docs/integrations/gluetun/index.mdx @@ -0,0 +1,52 @@ +--- +title: 'Gluetun' +description: 'Connect Gluetun to Homarr as a VPN integration.' +hide_title: true +--- + +import { IntegrationHeader } from '@site/src/components/integrations/header'; +import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; +import { AddingIntegration } from '@site/src/components/integrations/adding'; +import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { gluetunIntegration } from '.'; +import { vpnWidget } from '@site/docs/widgets/vpn'; + + + +[Gluetun](https://github.com/qdm12/gluetun) exposes a control server that Homarr can query to report the VPN tunnel +status, DNS status, public IP address, and active provider details in the VPN widget. + +### Widgets & Capabilities + + + +### Setting up the Gluetun control server + +Refer to the [Gluetun control server documentation](https://github.com/qdm12/gluetun-wiki/blob/main/setup/advanced/control-server.md#authentication) to enable and configure authentication. + +### Adding the integration + + + +### Secrets + +Gluetun's control server can be left unprotected or secured with either an API key or HTTP Basic authentication. +Choose the option that matches how your Gluetun instance integration is set up. + + diff --git a/apps/docs/docs/integrations/gluetun/index.ts b/apps/docs/docs/integrations/gluetun/index.ts new file mode 100644 index 000000000..6d2489a62 --- /dev/null +++ b/apps/docs/docs/integrations/gluetun/index.ts @@ -0,0 +1,8 @@ +import { IntegrationDefinition } from "@site/src/types"; + +export const gluetunIntegration: IntegrationDefinition = { + name: "Gluetun", + description: "VPN control server integration for Homarr's VPN widget.", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gluetun.svg", + path: "../../integrations/gluetun", +}; diff --git a/apps/docs/docs/widgets/vpn/img/single.png b/apps/docs/docs/widgets/vpn/img/single.png new file mode 100644 index 000000000..ea4b423e7 Binary files /dev/null and b/apps/docs/docs/widgets/vpn/img/single.png differ diff --git a/apps/docs/docs/widgets/vpn/index.mdx b/apps/docs/docs/widgets/vpn/index.mdx new file mode 100644 index 000000000..0aa6a1a16 --- /dev/null +++ b/apps/docs/docs/widgets/vpn/index.mdx @@ -0,0 +1,40 @@ +--- +title: 'VPN' +description: 'Monitor the status of your VPN integrations.' +hide_title: true +--- + +import { WidgetHeader } from '@site/src/components/widgets/header'; +import { AddingWidget } from '@site/src/components/widgets/adding'; +import { WidgetIntegrations } from '@site/src/components/widgets/integrations'; +import { vpnWidget } from '.'; +import { gluetunIntegration } from '@site/docs/integrations/gluetun'; + + + +The VPN widget provides a compact overview of each configured VPN integration. It shows whether the tunnel and DNS +services are up, the currently exposed public IP address, and the VPN provider and protocol being used. + +When multiple VPN integrations are attached, the widget renders one card per integration so you can compare their +current status at a glance. + +### Screenshots + +import singleIntegrationImage from './img/single.png'; + +
+ VPN widget showing a single integration +
+ +### Supported Integrations + + + +### Adding the widget + + diff --git a/apps/docs/docs/widgets/vpn/index.ts b/apps/docs/docs/widgets/vpn/index.ts new file mode 100644 index 000000000..0f1590e5b --- /dev/null +++ b/apps/docs/docs/widgets/vpn/index.ts @@ -0,0 +1,9 @@ +import { WidgetDefinition } from "@site/src/types"; +import { IconShieldLock } from "@tabler/icons-react"; + +export const vpnWidget: WidgetDefinition = { + icon: IconShieldLock, + name: "VPN", + description: "Monitor the connection status, public IP, and provider details of your VPN integrations.", + path: "../../widgets/vpn", +}; diff --git a/apps/nextjs/next.config.ts b/apps/nextjs/next.config.ts index 636df3f52..a00df48d8 100644 --- a/apps/nextjs/next.config.ts +++ b/apps/nextjs/next.config.ts @@ -31,6 +31,8 @@ const nextConfig: NextConfig = { }, output: "standalone", reactStrictMode: true, + // Ship browser source maps so production client stack traces are readable, see https://github.com/homarr-labs/homarr/issues/5891 + productionBrowserSourceMaps: true, // react compiler breaks mantine-react-table, so disabled for now //reactCompiler: true, /** We already do typechecking as separate tasks in CI */ @@ -41,6 +43,8 @@ const nextConfig: NextConfig = { */ serverExternalPackages: ["dockerode", "isomorphic-dompurify", "jsdom", "better-sqlite3"], experimental: { + // Ship server source maps so production Node stack traces in logs reference original source, see https://github.com/homarr-labs/homarr/issues/5891 + serverSourceMaps: true, optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"], turbopackFileSystemCacheForDev: true, preloadEntriesOnStart: false, diff --git a/apps/nextjs/src/app/[locale]/manage/about/page.tsx b/apps/nextjs/src/app/[locale]/manage/about/page.tsx index 3f49db49c..9577d39a0 100644 --- a/apps/nextjs/src/app/[locale]/manage/about/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/about/page.tsx @@ -1,4 +1,3 @@ -import { headers } from "next/headers"; import Image from "next/image"; import { Accordion, @@ -41,11 +40,10 @@ import { getScopedI18n } from "@homarr/translation/server"; import { homarrLogoPath } from "~/components/layout/logo/homarr-logo"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { createMetaTitle } from "~/metadata"; -import type { PackageJsonDependencies } from "~/versions/package-reader"; -import { getPackageVersion } from "~/versions/package-reader"; -import type githubContributorsJson from "../../../../../../../static-data/contributors.json"; -import type openCollectiveContributorsJson from "../../../../../../../static-data/opencollective-contributors.json"; -import type crowdinContributorsJson from "../../../../../../../static-data/translators.json"; +import { getDependenciesAsync, getPackageVersion } from "~/versions/package-reader"; +import githubContributors from "@static-data/contributors.json"; +import openCollectiveContributors from "@static-data/opencollective-contributors.json"; +import crowdinContributors from "@static-data/translators.json"; import classes from "./about.module.css"; export async function generateMetadata() { @@ -56,32 +54,10 @@ export async function generateMetadata() { }; } -const getHostAsync = async () => { - if (process.env.HOSTNAME) { - return `${process.env.HOSTNAME}:3000`; - } - - return (await headers()).get("host"); -}; - export default async function AboutPage() { - const baseServerUrl = `http://${await getHostAsync()}`; const t = await getScopedI18n("management.page.about"); const version = getPackageVersion(); - const dependencies = (await fetch(`${baseServerUrl}/api/about/dependencies`).then((res) => - res.json(), - )) as PackageJsonDependencies; - const githubContributors = (await fetch(`${baseServerUrl}/api/about/contributors/github`).then((res) => - res.json(), - )) as typeof githubContributorsJson; - - const crowdinContributors = (await fetch(`${baseServerUrl}/api/about/contributors/crowdin`).then((res) => - res.json(), - )) as typeof crowdinContributorsJson; - - const openCollectiveContributors = (await fetch(`${baseServerUrl}/api/about/contributors/opencollective`).then( - (res) => res.json(), - )) as typeof openCollectiveContributorsJson; + const dependencies = await getDependenciesAsync(); return (
@@ -185,7 +161,7 @@ export default async function AboutPage() { {Object.entries(dependencies) .filter(([, value]) => !value.includes("workspace:")) - .sort(([key1], [key2]) => key1.localeCompare(key2)) + .toSorted(([key1], [key2]) => key1.localeCompare(key2)) .map(([name, version]) => ( void; +}) { + const tError = useScopedI18n("management.error"); + const t = useI18n(); + + useEffect(() => { + console.error(error); + }, [error]); + + return ( +
+ + + {tError("title")} + + {tError("text")} + + {error.digest && ( + + {tError("digest", { digest: error.digest })} + + )} + + +
+ ); +} diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx index 6ebbdbb6d..a0622d5aa 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/test-connection/test-connection-certificate.tsx @@ -131,6 +131,7 @@ export const CertificateErrorDetails = ({ error, url }: CertificateErrorDetailsP {(error.data.reason === "untrusted" && rootCertificate.isSelfSigned) || error.data.reason === "hostnameMismatch" ? ( + + ); + } + if (isLoading) { + return Array(15) + .fill(0) + .map((_, index) => ( + + + + )); + } + if (totalOptions > 0) { + return {groups}; + } + return ( + + + {tCommon("iconPicker.noResults", { search: debouncedQuery })} + + ); + }; + return ( @@ -137,16 +172,11 @@ export const IconPicker = ({ } - leftSection={ - shouldShowPreview(previewUrl) ? : null - } - value={search} + leftSection={leftSection} + value={inputValue} onChange={(event) => { combobox.openDropdown(); - combobox.updateSelectedOptionIndex(); - setSearch(event.currentTarget.value); - setValue(event.currentTarget.value); - setPreviewUrl(null); + setQuery(event.currentTarget.value); }} onClick={() => combobox.openDropdown()} onFocus={(event) => { @@ -156,25 +186,21 @@ export const IconPicker = ({ onBlur={(event) => { onBlur?.(event); combobox.closeDropdown(); - setPreviewUrl(value); - setSearch(value || ""); + setQuery(""); }} rightSectionPointerEvents="none" withAsterisk={withAsterisk} error={error} label={label ?? tCommon("iconPicker.label")} - placeholder={placeholder ?? tCommon("iconPicker.header", { countIcons: String(data?.countIcons ?? 0) })} + placeholder={placeholderText} /> {session?.user.permissions.includes("media-upload") && ( { const first = medias.at(0); if (!first) return; - startTransition(() => { setValue(first.url); - setPreviewUrl(first.url); - setSearch(first.url); }); }} > @@ -190,17 +216,7 @@ export const IconPicker = ({ - {totalOptions > 0 ? ( - {groups} - ) : ( - Array(15) - .fill(0) - .map((_, index: number) => ( - - - - )) - )} + {renderDropdown()} @@ -209,8 +225,8 @@ export const IconPicker = ({ // This regex is used to prevent loading a preview like en or /en which would trigger a language change // See https://github.com/homarr-labs/homarr/issues/3070 -const localizationPathRegex = new RegExp(`^/?(${supportedLanguages.join("|")})(/.*)?$`, "i" /* ignore casing */); -const shouldShowPreview = (value: string | null): value is string => { +const localizationPathRegex = new RegExp(`^/?(${supportedLanguages.join("|")})(/.*)?$`, "i"); +const shouldShowPreview = (value: string | null | undefined): value is string => { if (!value) return false; return !localizationPathRegex.test(value); }; diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index 9d997e7c3..13ed36537 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -21,6 +21,7 @@ import { GitHubContainerRegistryIntegration } from "../github-container-registry import { GithubIntegration } from "../github/github-integration"; import { GitlabIntegration } from "../gitlab/gitlab-integration"; import { GlancesIntegration } from "../glances/glances-integration"; +import { GluetunIntegration } from "../gluetun/gluetun-integration"; import { HomeAssistantIntegration } from "../homeassistant/homeassistant-integration"; import { ICalIntegration } from "../ical/ical-integration"; import { ImmichIntegration } from "../immich/immich-integration"; @@ -137,6 +138,7 @@ export const integrationCreators = { audiobookshelf: AudiobookshelfIntegration, navidrome: NavidromeIntegration, umami: UmamiIntegration, + gluetun: GluetunIntegration, archiveTeamWarrior: ArchiveTeamWarriorIntegration, uptimeKuma: UptimeKumaIntegration, peaNut: PeaNutIntegration, diff --git a/packages/integrations/src/beszel/beszel-integration.ts b/packages/integrations/src/beszel/beszel-integration.ts index 50f64668c..bf6f3640c 100644 --- a/packages/integrations/src/beszel/beszel-integration.ts +++ b/packages/integrations/src/beszel/beszel-integration.ts @@ -46,10 +46,13 @@ export class BeszelIntegration extends Integration { private async authenticateAsync(): Promise { const existingSession = await this.sessionStore.getAsync(); if (existingSession) { + logger.debug("Using stored Beszel session", { integrationId: this.integration.id }); return existingSession; } - const response = await fetchWithTrustedCertificatesAsync(this.url("/api/collections/users/auth-with-password"), { + const authUrl = this.url("/api/collections/users/auth-with-password"); + logger.debug("Authenticating with Beszel", { integrationId: this.integration.id, url: authUrl.pathname }); + const response = await fetchWithTrustedCertificatesAsync(authUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ @@ -57,23 +60,28 @@ export class BeszelIntegration extends Integration { password: this.getSecretValue("password"), }), }); + logger.debug("Beszel auth response received", { integrationId: this.integration.id, status: response.status }); if (!response.ok) { + logger.warn("Beszel auth failed", { integrationId: this.integration.id, status: response.status }); throw new ResponseError(response); } const data = (await response.json()) as BeszelAuthResponse; const session: BeszelSession = { token: data.token, userId: data.record.id }; await this.sessionStore.setAsync(session); + logger.debug("Saved Beszel session", { integrationId: this.integration.id, userId: session.userId }); return session; } private async fetchWithAuthAsync(url: URL, options: { method?: string; body?: string } = {}) { + const method = options.method ?? "GET"; + const start = performance.now(); let session = await this.authenticateAsync(); const doFetch = (token: string) => fetchWithTrustedCertificatesAsync(url, { - method: options.method ?? "GET", + method, headers: { Authorization: token, ...(options.body ? { "Content-Type": "application/json" } : {}), @@ -82,14 +90,42 @@ export class BeszelIntegration extends Integration { }); let response = await doFetch(session.token); + logger.debug("Beszel response", { + integrationId: this.integration.id, + method, + path: url.pathname, + status: response.status, + durationMs: Math.round(performance.now() - start), + attempt: 1, + }); if (response.status === 401) { + logger.warn("Beszel 401, clearing session and retrying", { + integrationId: this.integration.id, + method, + path: url.pathname, + }); await this.sessionStore.clearAsync(); session = await this.authenticateAsync(); response = await doFetch(session.token); + logger.debug("Beszel response (after re-auth)", { + integrationId: this.integration.id, + method, + path: url.pathname, + status: response.status, + durationMs: Math.round(performance.now() - start), + attempt: 2, + }); } if (!response.ok) { + logger.warn("Beszel request failed", { + integrationId: this.integration.id, + method, + path: url.pathname, + status: response.status, + durationMs: Math.round(performance.now() - start), + }); throw new ResponseError(response); } @@ -257,6 +293,7 @@ export class BeszelIntegration extends Integration { ): Promise { const session = await this.authenticateAsync(); const sseUrl = this.url("/api/realtime"); + logger.debug("Opening Beszel SSE connection", { integrationId: this.integration.id, systemId }); const sseResponse = await fetchWithTrustedCertificatesAsync(sseUrl, { headers: { Authorization: session.token }, @@ -264,8 +301,14 @@ export class BeszelIntegration extends Integration { }); if (!sseResponse.ok || !sseResponse.body) { + logger.warn("Beszel SSE connection failed", { + integrationId: this.integration.id, + systemId, + status: sseResponse.status, + }); throw new ResponseError(sseResponse); } + logger.debug("Beszel SSE connection opened", { integrationId: this.integration.id, systemId }); const reader = sseResponse.body.getReader(); const decoder = new TextDecoder(); @@ -322,6 +365,10 @@ export class BeszelIntegration extends Integration { } } if (!signal.aborted) { + logger.warn("Beszel SSE stream ended unexpectedly", { + integrationId: this.integration.id, + systemId, + }); throw new Error("Beszel SSE stream ended unexpectedly"); } } finally { diff --git a/packages/integrations/src/gluetun/gluetun-integration.ts b/packages/integrations/src/gluetun/gluetun-integration.ts new file mode 100644 index 000000000..a150f0f18 --- /dev/null +++ b/packages/integrations/src/gluetun/gluetun-integration.ts @@ -0,0 +1,115 @@ +import { ResponseError } from "@homarr/common/server"; +import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; + +import type { IntegrationTestingInput } from "../base/integration"; +import { Integration } from "../base/integration"; +import { TestConnectionError } from "../base/test-connection/test-connection-error"; +import type { TestingResult } from "../base/test-connection/test-connection-service"; +import type { VpnSummaryIntegration } from "../interfaces/vpn-summary/vpn-summary-integration"; +import type { VpnSummary } from "../interfaces/vpn-summary/vpn-summary-types"; +import { + gluetunDnsStatusSchema, + gluetunPublicIpSchema, + gluetunVpnSettingsSchema, + gluetunVpnStatusSchema, +} from "./gluetun-types"; +import type { GluetunDnsStatus, GluetunPublicIp, GluetunVpnSettings, GluetunVpnStatus } from "./gluetun-types"; + +export class GluetunIntegration extends Integration implements VpnSummaryIntegration { + protected async testingAsync(input: IntegrationTestingInput): Promise { + const authHeaders = this.getAuthHeaders(); + const url = this.url("/v1/vpn/status"); + const response = await input.fetchAsync(url, { + headers: authHeaders, + }); + + if (!response.ok) { + return TestConnectionError.StatusResult(response); + } + + return { success: true }; + } + + public async getSummaryAsync(): Promise { + const authHeaders = this.getAuthHeaders(); + const [vpnStatus, dnsStatus, publicIp, vpnSettings] = await Promise.all([ + this.getVpnStatusAsync(authHeaders), + this.getDnsStatusAsync(authHeaders), + this.getPublicIpAsync(authHeaders), + this.getVpnSettingAsync(authHeaders), + ]); + + return { + vpnStatus: vpnStatus.status, + dnsStatus: dnsStatus.status, + publicIp: publicIp.public_ip, + country: publicIp.country, + city: publicIp.city, + vpnProvider: { + protocol: vpnSettings.type, + provider: vpnSettings.provider.name, + }, + }; + } + + private async getVpnStatusAsync(authHeaders: Record): Promise { + const url = this.url("/v1/vpn/status"); + + const response = await fetchWithTrustedCertificatesAsync(url, { + headers: authHeaders, + }); + + if (!response.ok) throw new ResponseError(response); + return gluetunVpnStatusSchema.parse(await response.json()); + } + + private async getDnsStatusAsync(authHeaders: Record): Promise { + const url = this.url("/v1/dns/status"); + + const response = await fetchWithTrustedCertificatesAsync(url, { + headers: authHeaders, + }); + + if (!response.ok) throw new ResponseError(response); + return gluetunDnsStatusSchema.parse(await response.json()); + } + + private async getPublicIpAsync(authHeaders: Record): Promise { + const url = this.url("/v1/publicip/ip"); + + const response = await fetchWithTrustedCertificatesAsync(url, { + headers: authHeaders, + }); + + if (!response.ok) throw new ResponseError(response); + return gluetunPublicIpSchema.parse(await response.json()); + } + + private async getVpnSettingAsync(authHeaders: Record): Promise { + const url = this.url("/v1/vpn/settings"); + + const response = await fetchWithTrustedCertificatesAsync(url, { + headers: authHeaders, + }); + + if (!response.ok) throw new ResponseError(response); + return gluetunVpnSettingsSchema.parse(await response.json()); + } + + private getAuthHeaders(): Record { + if (this.hasSecretValue("apiKey")) { + return { "X-API-Key": this.getSecretValue("apiKey") }; + } + + if (this.hasSecretValue("username") && this.hasSecretValue("password")) { + const username = this.getSecretValue("username"); + const password = this.getSecretValue("password"); + + const encodedCredentials = btoa(`${username}:${password}`); + + return { Authorization: `Basic ${encodedCredentials}` }; + } + + return {}; + } +} diff --git a/packages/integrations/src/gluetun/gluetun-types.ts b/packages/integrations/src/gluetun/gluetun-types.ts new file mode 100644 index 000000000..6886d72a7 --- /dev/null +++ b/packages/integrations/src/gluetun/gluetun-types.ts @@ -0,0 +1,116 @@ +import { z } from "zod/v4"; + +export const gluetunVpnStatusSchema = z.object({ + status: z.string(), +}); + +export type GluetunVpnStatus = z.infer; + +export const gluetunDnsStatusSchema = gluetunVpnStatusSchema; + +export type GluetunDnsStatus = z.infer; + +export const gluetunPublicIpSchema = z.object({ + public_ip: z.string(), + region: z.string(), + country: z.string(), + city: z.string(), + location: z.string(), + organization: z.string(), + postal_code: z.string(), + timezone: z.string(), +}); + +export type GluetunPublicIp = z.infer; + +const gluetunServerSelectionOpenvpnSchema = z.object({ + config_file_path: z.string(), + protocol: z.string(), + endpoint_ip: z.string(), + custom_port: z.number(), + pia_encryption_preset: z.string(), +}); + +const gluetunServerSelectionWireguardSchema = z.object({ + endpoint_ip: z.string(), + endpoint_port: z.number(), + public_key: z.string(), +}); + +const gluetunServerSelectionSchema = z.object({ + vpn: z.string(), + countries: z.array(z.string()).nullable(), + categories: z.array(z.string()).nullable(), + regions: z.array(z.string()).nullable(), + cities: z.array(z.string()).nullable(), + isps: z.array(z.string()).nullable(), + names: z.array(z.string()).nullable(), + numbers: z.array(z.number()).nullable(), + hostnames: z.array(z.string()), + owned_only: z.boolean(), + free_only: z.boolean(), + premium_only: z.boolean(), + stream_only: z.boolean(), + multi_hop_only: z.boolean(), + port_forward_only: z.boolean(), + secure_core_only: z.boolean(), + tor_only: z.boolean(), + openvpn: gluetunServerSelectionOpenvpnSchema, + wireguard: gluetunServerSelectionWireguardSchema, +}); + +const gluetunPortForwardingSchema = z.object({ + enabled: z.boolean(), + provider: z.string(), + status_file_path: z.string(), + up_command: z.string(), + down_command: z.string(), + listening_port: z.number(), + username: z.string(), + password: z.string(), +}); + +const gluetunProviderSchema = z.object({ + name: z.string(), + server_selection: gluetunServerSelectionSchema, + port_forwarding: gluetunPortForwardingSchema, +}); + +const gluetunOpenvpnSettingsSchema = z.object({ + version: z.string(), + user: z.string(), + password: z.string(), + config_file_path: z.string(), + ciphers: z.array(z.string()).nullable(), + auth: z.string(), + cert: z.string(), + key: z.string(), + encrypted_key: z.string(), + key_passphrase: z.string(), + pia_encryption_preset: z.string(), + mssfix: z.number(), + interface: z.string(), + process_user: z.string(), + verbosity: z.number(), + flags: z.array(z.string()).nullable(), +}); + +const gluetunWireguardSettingsSchema = z.object({ + private_key: z.string(), + pre_shared_key: z.string(), + addresses: z.array(z.string()), + allowed_ips: z.array(z.string()), + interface: z.string(), + persistent_keep_alive_interval: z.number(), + mtu: z.number(), + implementation: z.string(), +}); + +export const gluetunVpnSettingsSchema = z.object({ + type: z.string(), + provider: gluetunProviderSchema, + openvpn: gluetunOpenvpnSettingsSchema, + wireguard: gluetunWireguardSettingsSchema, +}); + +export type GluetunVpnSettings = z.infer; diff --git a/packages/integrations/src/gluetun/test/gluetun-integration.spec.ts b/packages/integrations/src/gluetun/test/gluetun-integration.spec.ts new file mode 100644 index 000000000..1f84005f3 --- /dev/null +++ b/packages/integrations/src/gluetun/test/gluetun-integration.spec.ts @@ -0,0 +1,371 @@ +import { Response } from "undici"; +import { beforeEach, describe, expect, test, vi } from "vitest"; + +import { createDb } from "@homarr/db/test"; + +import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; + +import type { IntegrationTestingInput } from "../../base/integration"; +import { GluetunIntegration } from "../gluetun-integration"; +import { + gluetunDnsStatusSchema, + gluetunPublicIpSchema, + gluetunVpnSettingsSchema, + gluetunVpnStatusSchema, +} from "../gluetun-types"; + +vi.mock("@homarr/db", async (importActual) => { + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + const actual = await importActual(); + return { + ...actual, + db: createDb(), + }; +}); + +vi.mock("@homarr/core/infrastructure/http", () => ({ + fetchWithTrustedCertificatesAsync: vi.fn(), +})); + +const TEST_URL = "https://gluetun.example.com"; +const TEST_API_KEY = "test-api-key"; +const TEST_USERNAME = "user"; +const TEST_PASSWORD = "p@ss"; + +const mockFetch = vi.mocked(fetchWithTrustedCertificatesAsync); + +type FetchResponse = Awaited>; + +const VPN_STATUS_PAYLOAD = { status: "running" }; +const DNS_STATUS_PAYLOAD = { status: "running" }; +const PUBLIC_IP_PAYLOAD = { + public_ip: "203.0.113.42", + region: "Europe", + country: "Germany", + city: "Berlin", + location: "52.5200,13.4050", + organization: "Example Org", + postal_code: "10115", + timezone: "Europe/Berlin", +}; +const VPN_SETTINGS_PAYLOAD = { + type: "wireguard", + provider: { + name: "mullvad", + server_selection: { + vpn: "wireguard", + countries: ["Germany"], + categories: null, + regions: null, + cities: ["Berlin"], + isps: null, + names: null, + numbers: null, + hostnames: ["de-ber-wg-001"], + owned_only: false, + free_only: false, + premium_only: false, + stream_only: false, + multi_hop_only: false, + port_forward_only: false, + secure_core_only: false, + tor_only: false, + openvpn: { + config_file_path: "", + protocol: "udp", + endpoint_ip: "", + custom_port: 0, + pia_encryption_preset: "", + }, + wireguard: { + endpoint_ip: "203.0.113.1", + endpoint_port: 51820, + public_key: "pubkey", + }, + }, + port_forwarding: { + enabled: false, + provider: "mullvad", + status_file_path: "", + up_command: "", + down_command: "", + listening_port: 0, + username: "", + password: "", + }, + }, + openvpn: { + version: "", + user: "", + password: "", + config_file_path: "", + ciphers: null, + auth: "", + cert: "", + key: "", + encrypted_key: "", + key_passphrase: "", + pia_encryption_preset: "", + mssfix: 0, + interface: "tun0", + process_user: "", + verbosity: 0, + flags: null, + }, + wireguard: { + private_key: "", + pre_shared_key: "", + addresses: ["10.0.0.2/32"], + allowed_ips: ["0.0.0.0/0"], + interface: "wg0", + persistent_keep_alive_interval: 25, + mtu: 1420, + implementation: "auto", + }, +}; + +const jsonResponse = (body: unknown, init: ResponseInit = { status: 200 }): FetchResponse => + new Response(JSON.stringify(body), { + ...init, + headers: { "content-type": "application/json" }, + }) as unknown as FetchResponse; + +const setupHappyPath = () => { + mockFetch.mockImplementation((url) => { + const urlString = typeof url === "string" ? url : url.toString(); + const { pathname } = new URL(urlString); + + switch (pathname) { + case "/v1/vpn/status": + return Promise.resolve(jsonResponse(VPN_STATUS_PAYLOAD)); + case "/v1/dns/status": + return Promise.resolve(jsonResponse(DNS_STATUS_PAYLOAD)); + case "/v1/publicip/ip": + return Promise.resolve(jsonResponse(PUBLIC_IP_PAYLOAD)); + case "/v1/vpn/settings": + return Promise.resolve(jsonResponse(VPN_SETTINGS_PAYLOAD)); + default: + return Promise.resolve(jsonResponse({ error: "not found" }, { status: 404 })); + } + }); +}; + +const createIntegrationWithApiKey = () => + new GluetunIntegration({ + id: "gluetun-1", + name: "Gluetun", + url: TEST_URL, + externalUrl: null, + decryptedSecrets: [{ kind: "apiKey", value: TEST_API_KEY }], + }); + +const createIntegrationWithBasicAuth = () => + new GluetunIntegration({ + id: "gluetun-2", + name: "Gluetun", + url: TEST_URL, + externalUrl: null, + decryptedSecrets: [ + { kind: "username", value: TEST_USERNAME }, + { kind: "password", value: TEST_PASSWORD }, + ], + }); + +describe("GluetunIntegration.getSummaryAsync", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test("maps the four upstream responses into a flat VPN summary", async () => { + setupHappyPath(); + + const result = await createIntegrationWithApiKey().getSummaryAsync(); + + expect(result).toEqual({ + vpnStatus: "running", + dnsStatus: "running", + publicIp: "203.0.113.42", + country: "Germany", + city: "Berlin", + vpnProvider: { + protocol: "wireguard", + provider: "mullvad", + }, + }); + }); + + test("hits each of the four control endpoints exactly once", async () => { + setupHappyPath(); + + await createIntegrationWithApiKey().getSummaryAsync(); + + const calledPaths = mockFetch.mock.calls.map(([url]) => { + const urlString = typeof url === "string" ? url : url.toString(); + return new URL(urlString).pathname; + }); + + expect(calledPaths).toHaveLength(4); + expect(new Set(calledPaths)).toEqual( + new Set(["/v1/vpn/status", "/v1/dns/status", "/v1/publicip/ip", "/v1/vpn/settings"]), + ); + }); + + test("sends X-API-Key header when an apiKey secret is configured", async () => { + setupHappyPath(); + + await createIntegrationWithApiKey().getSummaryAsync(); + + for (const [, init] of mockFetch.mock.calls) { + const headers = (init?.headers ?? {}) as Record; + expect(headers["X-API-Key"]).toBe(TEST_API_KEY); + expect(headers.Authorization).toBeUndefined(); + } + }); + + test("sends Basic auth header when username/password are configured", async () => { + setupHappyPath(); + + await createIntegrationWithBasicAuth().getSummaryAsync(); + + const expected = `Basic ${btoa(`${TEST_USERNAME}:${TEST_PASSWORD}`)}`; + for (const [, init] of mockFetch.mock.calls) { + const headers = (init?.headers ?? {}) as Record; + expect(headers.Authorization).toBe(expected); + expect(headers["X-API-Key"]).toBeUndefined(); + } + }); + + test("throws when any upstream endpoint returns a non-OK status", async () => { + mockFetch.mockImplementation((url) => { + const urlString = typeof url === "string" ? url : url.toString(); + const { pathname } = new URL(urlString); + + if (pathname === "/v1/publicip/ip") { + return Promise.resolve(jsonResponse({ error: "unauthorized" }, { status: 401 })); + } + return Promise.resolve(jsonResponse(VPN_STATUS_PAYLOAD)); + }); + + await expect(createIntegrationWithApiKey().getSummaryAsync()).rejects.toThrow(); + }); + + test("throws when an upstream payload fails schema validation", async () => { + mockFetch.mockImplementation((url) => { + const urlString = typeof url === "string" ? url : url.toString(); + const { pathname } = new URL(urlString); + + if (pathname === "/v1/publicip/ip") { + return Promise.resolve(jsonResponse({ public_ip: 123 })); + } + return Promise.resolve(jsonResponse(VPN_STATUS_PAYLOAD)); + }); + + await expect(createIntegrationWithApiKey().getSummaryAsync()).rejects.toThrow(); + }); +}); + +describe("GluetunIntegration testing endpoint", () => { + type TestingFn = (input: IntegrationTestingInput) => Promise<{ success: boolean }>; + + const invokeTesting = (integration: GluetunIntegration, input: IntegrationTestingInput) => { + const testing = (integration as unknown as { testingAsync: TestingFn }).testingAsync.bind(integration); + return testing(input); + }; + + const makeInput = (response: Response): IntegrationTestingInput => + ({ + fetchAsync: vi.fn().mockResolvedValue(response), + }) as unknown as IntegrationTestingInput; + + test("returns success when /v1/vpn/status responds 200", async () => { + const input = makeInput(new Response(JSON.stringify(VPN_STATUS_PAYLOAD), { status: 200 })); + + const result = await invokeTesting(createIntegrationWithApiKey(), input); + + expect(result.success).toBe(true); + }); + + test("returns a status-code failure when /v1/vpn/status responds non-OK", async () => { + const input = makeInput(new Response("unauthorized", { status: 401 })); + + const result = await invokeTesting(createIntegrationWithApiKey(), input); + + expect(result.success).toBe(false); + }); + + test("passes the api-key header through to fetchAsync", async () => { + const response = new Response(JSON.stringify(VPN_STATUS_PAYLOAD), { status: 200 }); + const input = makeInput(response); + + await invokeTesting(createIntegrationWithApiKey(), input); + + const fetchAsyncMock = vi.mocked(input.fetchAsync); + const init = fetchAsyncMock.mock.calls[0]?.[1]; + const headers = (init?.headers ?? {}) as Record; + expect(headers["X-API-Key"]).toBe(TEST_API_KEY); + }); + + test("passes the Basic auth header through to fetchAsync when username/password are configured", async () => { + const response = new Response(JSON.stringify(VPN_STATUS_PAYLOAD), { status: 200 }); + const input = makeInput(response); + + await invokeTesting(createIntegrationWithBasicAuth(), input); + + const fetchAsyncMock = vi.mocked(input.fetchAsync); + const init = fetchAsyncMock.mock.calls[0]?.[1]; + const headers = (init?.headers ?? {}) as Record; + const expected = `Basic ${btoa(`${TEST_USERNAME}:${TEST_PASSWORD}`)}`; + expect(headers.Authorization).toBe(expected); + expect(headers["X-API-Key"]).toBeUndefined(); + }); +}); + +describe("gluetun schemas", () => { + test("vpn status schema accepts a string status", () => { + expect(gluetunVpnStatusSchema.parse({ status: "running" })).toEqual({ status: "running" }); + }); + + test("vpn status schema rejects a missing status", () => { + expect(() => gluetunVpnStatusSchema.parse({})).toThrow(); + }); + + test("dns status schema mirrors vpn status schema", () => { + expect(gluetunDnsStatusSchema.parse({ status: "stopped" })).toEqual({ status: "stopped" }); + expect(() => gluetunDnsStatusSchema.parse({ status: 42 })).toThrow(); + }); + + test("public ip schema parses the full payload", () => { + expect(gluetunPublicIpSchema.parse(PUBLIC_IP_PAYLOAD)).toEqual(PUBLIC_IP_PAYLOAD); + }); + + test("public ip schema rejects a missing required field", () => { + const { city: _city, ...partial } = PUBLIC_IP_PAYLOAD; + expect(() => gluetunPublicIpSchema.parse(partial)).toThrow(); + }); + + test("vpn settings schema parses a wireguard payload", () => { + const parsed = gluetunVpnSettingsSchema.parse(VPN_SETTINGS_PAYLOAD); + expect(parsed.type).toBe("wireguard"); + expect(parsed.provider.name).toBe("mullvad"); + }); + + test("vpn settings schema accepts nullable server-selection arrays", () => { + const payloadWithNulls = { + ...VPN_SETTINGS_PAYLOAD, + provider: { + ...VPN_SETTINGS_PAYLOAD.provider, + server_selection: { + ...VPN_SETTINGS_PAYLOAD.provider.server_selection, + countries: null, + cities: null, + }, + }, + }; + + expect(() => gluetunVpnSettingsSchema.parse(payloadWithNulls)).not.toThrow(); + }); + + test("vpn settings schema rejects a non-string type", () => { + expect(() => gluetunVpnSettingsSchema.parse({ ...VPN_SETTINGS_PAYLOAD, type: 1 })).toThrow(); + }); +}); diff --git a/packages/integrations/src/gotify/gotify-integration.ts b/packages/integrations/src/gotify/gotify-integration.ts index b7fd9361e..1d0f5eb8c 100644 --- a/packages/integrations/src/gotify/gotify-integration.ts +++ b/packages/integrations/src/gotify/gotify-integration.ts @@ -15,9 +15,9 @@ export class GotifyIntegration extends Integration implements INotificationsInte } private getHeaders() { - const credentials = Buffer.from( - `${super.getSecretValue("username")}:${super.getSecretValue("password")}`, - ).toString("base64"); + const credentials = Buffer.from(`${super.getSecretValue("username")}:${super.getSecretValue("password")}`).toString( + "base64", + ); return { Authorization: `Basic ${credentials}` }; } @@ -31,11 +31,13 @@ export class GotifyIntegration extends Integration implements INotificationsInte if (!result.success) throw new Error(`Failed to parse Gotify response: ${result.error.message}`); const parsed = result.data; - return parsed.messages.map((message): Notification => ({ - id: String(message.id), - time: new Date(message.date), - title: message.title, - body: message.message, - })); + return parsed.messages.map( + (message): Notification => ({ + id: String(message.id), + time: new Date(message.date), + title: message.title, + body: message.message, + }), + ); } } diff --git a/packages/integrations/src/interfaces/vpn-summary/vpn-summary-integration.ts b/packages/integrations/src/interfaces/vpn-summary/vpn-summary-integration.ts new file mode 100644 index 000000000..39e500d30 --- /dev/null +++ b/packages/integrations/src/interfaces/vpn-summary/vpn-summary-integration.ts @@ -0,0 +1,5 @@ +import type { VpnSummary } from "./vpn-summary-types"; + +export interface VpnSummaryIntegration { + getSummaryAsync(): Promise; +} diff --git a/packages/integrations/src/interfaces/vpn-summary/vpn-summary-types.ts b/packages/integrations/src/interfaces/vpn-summary/vpn-summary-types.ts new file mode 100644 index 000000000..91e70454c --- /dev/null +++ b/packages/integrations/src/interfaces/vpn-summary/vpn-summary-types.ts @@ -0,0 +1,13 @@ +export interface VpnProviderDetails { + protocol: string; + provider: string; +} + +export interface VpnSummary { + vpnStatus: string; + dnsStatus: string; + publicIp: string; + country: string; + city: string; + vpnProvider: VpnProviderDetails; +} diff --git a/packages/integrations/src/plex/plex-integration.ts b/packages/integrations/src/plex/plex-integration.ts index 9c2cb8a4f..a031343c0 100644 --- a/packages/integrations/src/plex/plex-integration.ts +++ b/packages/integrations/src/plex/plex-integration.ts @@ -127,11 +127,18 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat const media = data.MediaContainer.Metadata?.filter((item) => item.Image).map((item) => { + const title = + item.type === "episode" + ? (item.grandparentTitle ?? item.title) + : item.type === "season" + ? (item.parentTitle ?? item.title) + : item.title; + return { id: item.Media?.at(0)?.id.toString() ?? item.key, type: mapType(item.type), - title: item.title, - subtitle: item.tagline, + title, + subtitle: title === item.title ? item.tagline : item.title, description: item.summary, releaseDate: item.originallyAvailableAt ? new Date(item.originallyAvailableAt) @@ -222,6 +229,8 @@ const recentlyAddedSchema = z.object({ studio: z.string().optional(), type: z.string(), // For example "movie", "album" title: z.string(), + parentTitle: z.string().optional(), + grandparentTitle: z.string().optional(), summary: z.string().optional(), duration: z.number().optional(), addedAt: z.number(), diff --git a/packages/integrations/src/plex/test/plex-integration.spec.ts b/packages/integrations/src/plex/test/plex-integration.spec.ts new file mode 100644 index 000000000..64e046256 --- /dev/null +++ b/packages/integrations/src/plex/test/plex-integration.spec.ts @@ -0,0 +1,140 @@ +// @vitest-environment node +import { Response } from "undici"; +import { beforeEach, describe, expect, test, vi } from "vitest"; + +import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; + +import type { IntegrationSecret } from "../../base/types"; +import { PlexIntegration } from "../plex-integration"; + +const imageProxyMocks = vi.hoisted(() => ({ + createImageAsync: vi.fn((url: string) => Promise.resolve(`proxied:${url}`)), +})); + +vi.mock("@homarr/core/infrastructure/http", () => ({ + fetchWithTrustedCertificatesAsync: vi.fn(), +})); + +vi.mock("@homarr/image-proxy", () => ({ + ImageProxy: class { + createImageAsync = imageProxyMocks.createImageAsync; + }, +})); + +const TEST_URL = "https://plex.example.com"; +const mockFetch = vi.mocked(fetchWithTrustedCertificatesAsync); + +const secrets: IntegrationSecret[] = [{ kind: "apiKey", value: "plex-token" }]; + +const createIntegration = () => + new PlexIntegration({ + id: "test-plex", + name: "Test Plex", + url: TEST_URL, + externalUrl: null, + decryptedSecrets: secrets, + }); + +const createMetadataItem = (key: string, overrides: Record) => ({ + key: `/library/metadata/${key}`, + type: "movie", + title: "Movie", + addedAt: 1_735_689_600, + Image: [ + { + type: "coverPoster", + url: `/library/metadata/${key}/thumb`, + }, + ], + ...overrides, +}); + +beforeEach(() => { + mockFetch.mockReset(); + imageProxyMocks.createImageAsync.mockClear(); +}); + +describe("PlexIntegration.getMediaReleasesAsync", () => { + test("uses the series title for TV seasons and episodes", async () => { + mockFetch.mockImplementation((url) => { + const urlString = String(url); + + if (urlString.endsWith("/identity")) { + return Promise.resolve( + new Response(JSON.stringify({ MediaContainer: { machineIdentifier: "server-id" } }), { status: 200 }), + ) as unknown as ReturnType; + } + + if (urlString.endsWith("/library/recentlyAdded")) { + return Promise.resolve( + new Response( + JSON.stringify({ + MediaContainer: { + Metadata: [ + createMetadataItem("season", { + type: "season", + title: "Season 1", + parentTitle: "Breaking Bad", + }), + createMetadataItem("episode", { + type: "episode", + title: "Review", + parentTitle: "Season 1", + grandparentTitle: "The Bear", + }), + createMetadataItem("movie", { + type: "movie", + title: "Inception", + tagline: "Dreams feel real", + }), + createMetadataItem("show", { + type: "show", + title: "The Last of Us", + tagline: "A series tagline", + }), + createMetadataItem("missing-parent", { + type: "season", + title: "Season 3", + }), + ], + }, + }), + { status: 200 }, + ), + ) as unknown as ReturnType; + } + + throw new Error(`Unexpected Plex request: ${urlString}`); + }); + + const releases = await createIntegration().getMediaReleasesAsync(); + + expect(releases).toMatchObject([ + { + title: "Breaking Bad", + subtitle: "Season 1", + type: "tv", + }, + { + title: "The Bear", + subtitle: "Review", + type: "tv", + }, + { + title: "Inception", + subtitle: "Dreams feel real", + type: "movie", + }, + { + title: "The Last of Us", + subtitle: "A series tagline", + type: "tv", + }, + { + title: "Season 3", + subtitle: undefined, + type: "tv", + }, + ]); + }); +}); \ No newline at end of file diff --git a/packages/integrations/src/truenas/test/truenas-integration.spec.ts b/packages/integrations/src/truenas/test/truenas-integration.spec.ts index 28ff3b8d1..91ab0662c 100644 --- a/packages/integrations/src/truenas/test/truenas-integration.spec.ts +++ b/packages/integrations/src/truenas/test/truenas-integration.spec.ts @@ -132,8 +132,9 @@ const happyResponder = (method: string) => { aggregations: emptyAggregations(), start: 0, end: 1, - legend: [], - data: [[1000, 8_000_000_000]], + // The "memory" graph reports available (free) memory: legend is ["time", "available"]. + legend: ["time", "available"], + data: [[1000, 6_000_000_000]], }, { name: "cputemp", @@ -194,15 +195,17 @@ describe("TrueNasIntegration", () => { version: "TrueNAS-SCALE-24.10", cpuModelName: "Intel Xeon", cpuTemp: 45, - memAvailableInBytes: 16_000_000_000, - memUsedInBytes: 8_000_000_000, + // physmem (16 GB) minus the reported available 6 GB leaves 10 GB used. + memAvailableInBytes: 6_000_000_000, + memUsedInBytes: 10_000_000_000, uptime: 3600, rebootRequired: false, availablePkgUpdates: 0, loadAverage: null, gpu: [], network: { up: 20_000, down: 10_000 }, - fileSystem: [{ deviceName: "tank", available: "1000", used: "500", percentage: 50 }], + // `available` is the free space left on the pool (free = 500), not its total size. + fileSystem: [{ deviceName: "tank", available: "500", used: "500", percentage: 50 }], smart: [{ deviceName: "tank", healthy: true, overallStatus: "ONLINE", temperature: null }], }); }); diff --git a/packages/integrations/src/truenas/truenas-integration.ts b/packages/integrations/src/truenas/truenas-integration.ts index adbe32b3b..21f526201 100644 --- a/packages/integrations/src/truenas/truenas-integration.ts +++ b/packages/integrations/src/truenas/truenas-integration.ts @@ -37,14 +37,19 @@ export class TrueNasIntegration extends Integration implements ISystemHealthMoni const upload = this.extractNetworkTrafficData(netdata, 2); // Index 2 is "sent" const download = this.extractNetworkTrafficData(netdata, 1); // Index 1 is "received" + // The "memory" reporting graph reports available (free) memory, its legend is ["time", "available"]. + // Used memory is therefore the physical total minus what is still available (clamped against timing skew). + const memAvailableInBytes = memoryData[1] ?? 0; // Index 0 is the UNIX timestamp, Index 1 is available bytes + const memUsedInBytes = Math.max(systemInformation.physmem - memAvailableInBytes, 0); + return { cpuUtilization: cpuData.reduce((acc, item) => acc + (item > 100 ? 0 : item), 0) / cpuData.length, cpuTemp: Math.max(...cpuTempData.filter((_item, index) => index > 0)), - memAvailableInBytes: systemInformation.physmem, - memUsedInBytes: memoryData[1] ?? 0, // Index 0 is UNIX timestamp, Index 1 is free space in bytes + memAvailableInBytes, + memUsedInBytes, fileSystem: datasets.map((dataset) => ({ deviceName: dataset.name, - available: `${dataset.size}`, // TODO: can we use number instead of string here? + available: `${dataset.free}`, // free space left on the pool used: `${dataset.allocated}`, percentage: (dataset.allocated / dataset.size) * 100, })), diff --git a/packages/integrations/src/types.ts b/packages/integrations/src/types.ts index 1ee395dfa..afeaf1db2 100644 --- a/packages/integrations/src/types.ts +++ b/packages/integrations/src/types.ts @@ -4,6 +4,7 @@ export * from "./interfaces/network-controller-summary/network-controller-summar export * from "./interfaces/firewall-summary/firewall-summary-types"; export * from "./interfaces/health-monitoring/health-monitoring-types"; export * from "./interfaces/ups-summary/ups-summary-types"; +export * from "./interfaces/vpn-summary/vpn-summary-types"; export * from "./interfaces/indexer-manager/indexer-manager-types"; export * from "./interfaces/media-requests/media-request-types"; export * from "./base/searchable-integration"; @@ -22,4 +23,5 @@ export * from "./audiobookshelf/audiobookshelf-types"; export * from "./navidrome/navidrome-types"; export * from "./paperless-ngx/paperless-ngx-types"; export * from "./umami/umami-types"; +export * from "./gluetun/gluetun-types"; export * from "./beszel/beszel-types"; diff --git a/packages/integrations/src/unraid/unraid-integration.ts b/packages/integrations/src/unraid/unraid-integration.ts index 38b12c31d..bf8e77d3b 100644 --- a/packages/integrations/src/unraid/unraid-integration.ts +++ b/packages/integrations/src/unraid/unraid-integration.ts @@ -59,8 +59,8 @@ export class UnraidIntegration extends Integration implements ISystemHealthMonit cpuTemp: undefined, // Not implemented, see https://github.com/unraid/api/issues/1597 fileSystem: systemInfo.array.disks.map((disk) => ({ deviceName: disk.name, - used: humanFileSize(disk.fsUsed * 1024), // API is in KiB (kibibytes), covert to bytes - available: `${disk.size * 1024}`, // API is in KiB (kibibytes), covert to bytes + used: humanFileSize(disk.fsUsed * 1024), // API is in KiB (kibibytes), convert to bytes + available: `${(disk.size - disk.fsUsed) * 1024}`, // free space left on the disk, API is in KiB (kibibytes) percentage: (disk.fsUsed / disk.size) * 100, // The units are the same, therefore the actual unit is irrelevant })), smart: systemInfo.array.disks.map((disk) => ({ diff --git a/packages/integrations/test/technitium.spec.ts b/packages/integrations/test/technitium.spec.ts index 99c9d2610..77189b556 100644 --- a/packages/integrations/test/technitium.spec.ts +++ b/packages/integrations/test/technitium.spec.ts @@ -2,15 +2,7 @@ import type { StartedTestContainer } from "testcontainers"; import { GenericContainer, Wait } from "testcontainers"; -import { - beforeAll, - beforeEach, - afterAll, - describe, - expect, - test, - vi, -} from "vitest"; +import { beforeAll, beforeEach, afterAll, describe, expect, test, vi } from "vitest"; import { createDb } from "@homarr/db/test"; @@ -31,15 +23,10 @@ vi.mock("@homarr/db", async (importActual) => { vi.mock("@homarr/core/infrastructure/certificates", async (importActual) => { // eslint-disable-next-line @typescript-eslint/consistent-type-imports - const actual = - await importActual< - typeof import("@homarr/core/infrastructure/certificates") - >(); + const actual = await importActual(); return { ...actual, - getTrustedCertificateHostnamesAsync: vi - .fn() - .mockImplementation(() => Promise.resolve([])), + getTrustedCertificateHostnamesAsync: vi.fn().mockImplementation(() => Promise.resolve([])), }; }); @@ -90,9 +77,7 @@ const INTEGRATION_ID = "test-technitium"; const makeInput = ( baseUrl: string, - auth: - | { kind: "credentials"; password?: string } - | { kind: "apiKey"; value: string }, + auth: { kind: "credentials"; password?: string } | { kind: "apiKey"; value: string }, ): IntegrationInput => ({ id: INTEGRATION_ID, name: "Technitium DNS", @@ -109,10 +94,7 @@ const makeInput = ( // Fetch an API token appropriate for the server version. // v15 has a dedicated createToken endpoint; legacy reuses the session token from login. -async function fetchApiToken( - baseUrl: string, - apiVersion: TechnitiumVersion, -): Promise { +async function fetchApiToken(baseUrl: string, apiVersion: TechnitiumVersion): Promise { if (apiVersion === "v15") { // v15 exposes a dedicated endpoint for non-expiring API tokens. const res = await fetch( @@ -122,9 +104,7 @@ async function fetchApiToken( } // Legacy: /api/user/login exists on all tested versions (v11–v14) and returns a session // token that can be used as a long-lived API key via the ?token= query parameter. - const res = await fetch( - `${baseUrl}/api/user/login?user=${DEFAULT_USERNAME}&pass=${DEFAULT_PASSWORD}`, - ); + const res = await fetch(`${baseUrl}/api/user/login?user=${DEFAULT_USERNAME}&pass=${DEFAULT_PASSWORD}`); return ((await res.json()) as { token: string }).token; } @@ -144,16 +124,12 @@ const pool: Record = {}; beforeAll(async () => { await Promise.all( VERSIONS.map(async ({ tag, apiVersion }) => { - const container = await new GenericContainer( - `technitium/dns-server:${tag}`, - ) + const container = await new GenericContainer(`technitium/dns-server:${tag}`) .withExposedPorts(5380) // Explicitly set the admin password so all versions use the same credentials. // Without this, older versions may generate a random password on first run. .withEnvironment({ DNS_SERVER_ADMIN_PASSWORD: DEFAULT_PASSWORD }) - .withWaitStrategy( - Wait.forLogMessage("Technitium DNS Server was started successfully."), - ) + .withWaitStrategy(Wait.forLogMessage("Technitium DNS Server was started successfully.")) .start(); const baseUrl = `http://${container.getHost()}:${container.getMappedPort(5380)}`; const apiToken = await fetchApiToken(baseUrl, apiVersion); @@ -163,238 +139,209 @@ beforeAll(async () => { }, 120_000); afterAll(async () => { - await Promise.all( - Object.values(pool).map(({ container }) => container.stop()), - ); + await Promise.all(Object.values(pool).map(({ container }) => container.stop())); }); // ─── version-parameterised suites ──────────────────────────────────────────── -describe.each(VERSIONS)( - "Technitium DNS $tag ($apiVersion)", - ({ tag, apiVersion }) => { - let baseUrl: string; - let apiToken: string; +describe.each(VERSIONS)("Technitium DNS $tag ($apiVersion)", ({ tag, apiVersion }) => { + let baseUrl: string; + let apiToken: string; - beforeAll(() => { - const entry = pool[tag]; - if (!entry) - throw new Error(`Container pool entry for ${tag} was not initialized`); - ({ baseUrl, apiToken } = entry); - }); + beforeAll(() => { + const entry = pool[tag]; + if (!entry) throw new Error(`Container pool entry for ${tag} was not initialized`); + ({ baseUrl, apiToken } = entry); + }); - beforeEach(() => { - sessionState[INTEGRATION_ID] = null; - }); + beforeEach(() => { + sessionState[INTEGRATION_ID] = null; + }); - // ── factory ──────────────────────────────────────────────────────────────── + // ── factory ──────────────────────────────────────────────────────────────── - describe("createTechnitiumDnsIntegrationAsync (factory)", () => { - test("factory creates a working integration (auto-detects version)", async () => { - const integration = await createTechnitiumDnsIntegrationAsync( - makeInput(baseUrl, { kind: "credentials" }), - ); + describe("createTechnitiumDnsIntegrationAsync (factory)", () => { + test("factory creates a working integration (auto-detects version)", async () => { + const integration = await createTechnitiumDnsIntegrationAsync(makeInput(baseUrl, { kind: "credentials" })); - const result = await integration.getSummaryAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("enabled"); - expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); - }, 20_000); - }); + expect(result.status).toBe("enabled"); + expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); + }, 20_000); + }); - // ── getSummaryAsync ──────────────────────────────────────────────────────── + // ── getSummaryAsync ──────────────────────────────────────────────────────── - describe("getSummaryAsync", () => { - test("returns valid summary with credentials", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + describe("getSummaryAsync", () => { + test("returns valid summary with credentials", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - const result = await integration.getSummaryAsync(); + const result = await integration.getSummaryAsync(); - expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); - expect(result.adsBlockedToday).toBeGreaterThanOrEqual(0); - expect(result.adsBlockedTodayPercentage).toBeGreaterThanOrEqual(0); - expect(result.domainsBeingBlocked).toBeGreaterThanOrEqual(0); - expect(result.status).toBe("enabled"); - }, 20_000); + expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); + expect(result.adsBlockedToday).toBeGreaterThanOrEqual(0); + expect(result.adsBlockedTodayPercentage).toBeGreaterThanOrEqual(0); + expect(result.domainsBeingBlocked).toBeGreaterThanOrEqual(0); + expect(result.status).toBe("enabled"); + }, 20_000); - test("returns valid summary with API key", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "apiKey", value: apiToken }), - apiVersion, - ); + test("returns valid summary with API key", async () => { + const integration = new TechnitiumDnsIntegration( + makeInput(baseUrl, { kind: "apiKey", value: apiToken }), + apiVersion, + ); - const result = await integration.getSummaryAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("enabled"); - expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); - }, 20_000); + expect(result.status).toBe("enabled"); + expect(result.dnsQueriesToday).toBeGreaterThanOrEqual(0); + }, 20_000); - test("domainsBeingBlocked is a non-negative number (blockedZones + blockListZones)", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + test("domainsBeingBlocked is a non-negative number (blockedZones + blockListZones)", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - const result = await integration.getSummaryAsync(); + const result = await integration.getSummaryAsync(); - expect(typeof result.domainsBeingBlocked).toBe("number"); - expect(result.domainsBeingBlocked).toBeGreaterThanOrEqual(0); - }, 20_000); - }); + expect(typeof result.domainsBeingBlocked).toBe("number"); + expect(result.domainsBeingBlocked).toBeGreaterThanOrEqual(0); + }, 20_000); + }); - // ── session caching ──────────────────────────────────────────────────────── + // ── session caching ──────────────────────────────────────────────────────── - describe("session caching", () => { - test("login is performed once and token is cached for subsequent calls", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + describe("session caching", () => { + test("login is performed once and token is cached for subsequent calls", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.getSummaryAsync(); - const tokenAfterFirst = sessionState[INTEGRATION_ID]?.token; - expect(tokenAfterFirst).toBeDefined(); + await integration.getSummaryAsync(); + const tokenAfterFirst = sessionState[INTEGRATION_ID]?.token; + expect(tokenAfterFirst).toBeDefined(); - await integration.getSummaryAsync(); - const tokenAfterSecond = sessionState[INTEGRATION_ID]?.token; + await integration.getSummaryAsync(); + const tokenAfterSecond = sessionState[INTEGRATION_ID]?.token; - expect(tokenAfterSecond).toBe(tokenAfterFirst); - }, 20_000); + expect(tokenAfterSecond).toBe(tokenAfterFirst); + }, 20_000); - test("recovers from an expired/invalid stored token by re-logging in", async () => { - // Plant a bad token with the correct version so it hits the right API path before failing - sessionState[INTEGRATION_ID] = { - token: "deliberately-invalid-token", - version: apiVersion, - }; + test("recovers from an expired/invalid stored token by re-logging in", async () => { + // Plant a bad token with the correct version so it hits the right API path before failing + sessionState[INTEGRATION_ID] = { + token: "deliberately-invalid-token", + version: apiVersion, + }; - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - apiVersion, - ); + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" }), apiVersion); - const result = await integration.getSummaryAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("enabled"); - expect(sessionState[INTEGRATION_ID]).not.toBeNull(); - expect(sessionState[INTEGRATION_ID]?.token).not.toBe( - "deliberately-invalid-token", - ); - }, 20_000); - }); + expect(result.status).toBe("enabled"); + expect(sessionState[INTEGRATION_ID]).not.toBeNull(); + expect(sessionState[INTEGRATION_ID]?.token).not.toBe("deliberately-invalid-token"); + }, 20_000); + }); - // ── blocking state changes ───────────────────────────────────────────────── + // ── blocking state changes ───────────────────────────────────────────────── - describe("blocking state changes", () => { - test("disableAsync permanently disables blocking", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + describe("blocking state changes", () => { + test("disableAsync permanently disables blocking", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.disableAsync(); - const result = await integration.getSummaryAsync(); + await integration.disableAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("disabled"); + expect(result.status).toBe("disabled"); - await integration.enableAsync(); // restore - }, 20_000); + await integration.enableAsync(); // restore + }, 20_000); - test("enableAsync re-enables blocking after permanent disable", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + test("enableAsync re-enables blocking after permanent disable", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.disableAsync(); - await integration.enableAsync(); - const result = await integration.getSummaryAsync(); + await integration.disableAsync(); + await integration.enableAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("enabled"); - }, 20_000); + expect(result.status).toBe("enabled"); + }, 20_000); - test("disableAsync with duration temporarily disables blocking", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + test("disableAsync with duration temporarily disables blocking", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.disableAsync(120); // 120s → 2 min - const result = await integration.getSummaryAsync(); + await integration.disableAsync(120); // 120s → 2 min + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("disabled"); + expect(result.status).toBe("disabled"); - await integration.enableAsync(); // restore - }, 20_000); + await integration.enableAsync(); // restore + }, 20_000); - test("disableAsync with small duration (1s) rounds up to 1 minute and disables", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + test("disableAsync with small duration (1s) rounds up to 1 minute and disables", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.disableAsync(1); - const result = await integration.getSummaryAsync(); + await integration.disableAsync(1); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("disabled"); + expect(result.status).toBe("disabled"); - await integration.enableAsync(); // restore - }, 20_000); + await integration.enableAsync(); // restore + }, 20_000); - test("enableAsync cancels an active timed disable immediately", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ); + test("enableAsync cancels an active timed disable immediately", async () => { + const integration = new TechnitiumDnsIntegration(makeInput(baseUrl, { kind: "credentials" })); - await integration.disableAsync(600); // 10 minutes - await integration.enableAsync(); - const result = await integration.getSummaryAsync(); + await integration.disableAsync(600); // 10 minutes + await integration.enableAsync(); + const result = await integration.getSummaryAsync(); - expect(result.status).toBe("enabled"); - }, 20_000); - }); + expect(result.status).toBe("enabled"); + }, 20_000); + }); - // ── testConnectionAsync ──────────────────────────────────────────────────── + // ── testConnectionAsync ──────────────────────────────────────────────────── - describe("testConnectionAsync", () => { - test("succeeds with valid credentials", async () => { - const result = await new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "credentials" }), - ).testConnectionAsync(); - expect(result.success).toBe(true); - }, 20_000); + describe("testConnectionAsync", () => { + test("succeeds with valid credentials", async () => { + const result = await new TechnitiumDnsIntegration( + makeInput(baseUrl, { kind: "credentials" }), + ).testConnectionAsync(); + expect(result.success).toBe(true); + }, 20_000); - test("succeeds with valid API key", async () => { - const result = await new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "apiKey", value: apiToken }), - apiVersion, - ).testConnectionAsync(); - expect(result.success).toBe(true); - }, 20_000); + test("succeeds with valid API key", async () => { + const result = await new TechnitiumDnsIntegration( + makeInput(baseUrl, { kind: "apiKey", value: apiToken }), + apiVersion, + ).testConnectionAsync(); + expect(result.success).toBe(true); + }, 20_000); - test("fails with wrong password — returns authorization error", async () => { - const integration = new TechnitiumDnsIntegration( - makeInput(baseUrl, { - kind: "credentials", - password: "wrong-password", - }), - ); + test("fails with wrong password — returns authorization error", async () => { + const integration = new TechnitiumDnsIntegration( + makeInput(baseUrl, { + kind: "credentials", + password: "wrong-password", + }), + ); - const result = await integration.testConnectionAsync(); + const result = await integration.testConnectionAsync(); - expect(result.success).toBe(false); - if (result.success) return; - expect(result.error).toBeInstanceOf(TestConnectionError); - expect(result.error.type).toBe("authorization"); - }, 20_000); + expect(result.success).toBe(false); + if (result.success) return; + expect(result.error).toBeInstanceOf(TestConnectionError); + expect(result.error.type).toBe("authorization"); + }, 20_000); - test("fails with invalid API key — returns authorization error", async () => { - const result = await new TechnitiumDnsIntegration( - makeInput(baseUrl, { kind: "apiKey", value: "invalid-api-key-xyz" }), - apiVersion, - ).testConnectionAsync(); + test("fails with invalid API key — returns authorization error", async () => { + const result = await new TechnitiumDnsIntegration( + makeInput(baseUrl, { kind: "apiKey", value: "invalid-api-key-xyz" }), + apiVersion, + ).testConnectionAsync(); - expect(result.success).toBe(false); - if (result.success) return; - expect(result.error).toBeInstanceOf(TestConnectionError); - expect(result.error.type).toBe("authorization"); - }, 20_000); - }); - }, -); + expect(result.success).toBe(false); + if (result.success) return; + expect(result.error).toBeInstanceOf(TestConnectionError); + expect(result.error.type).toBe("authorization"); + }, 20_000); + }); +}); diff --git a/packages/redis/src/index.ts b/packages/redis/src/index.ts index 8e6e3db86..6c99c11b6 100644 --- a/packages/redis/src/index.ts +++ b/packages/redis/src/index.ts @@ -15,6 +15,7 @@ export { createGetSetChannel, createQueryCacheChannel, getAllQueryCacheAsync, + invalidateIntegrationCacheAsync, } from "./lib/channel"; export { createIntegrationHistoryChannel } from "./lib/channels/history-channel"; diff --git a/packages/redis/src/lib/channel.ts b/packages/redis/src/lib/channel.ts index 9f2b04a98..d04d1499a 100644 --- a/packages/redis/src/lib/channel.ts +++ b/packages/redis/src/lib/channel.ts @@ -261,6 +261,36 @@ export const createIntegrationOptionsChannel = ( return createChannelWithLatestAndEvents(channelName); }; +/** + * Invalidates all cached data for a given integration by deleting every Redis key + * that starts with `integration:${integrationId}:` as well as the integration's + * session store entry. This ensures that stale data from a misconfigured or + * updated integration is never served from cache. + */ +export const invalidateIntegrationCacheAsync = async (integrationId: string): Promise => { + const client = getSetClient as typeof getSetClient | null; + if (!client) { + return; + } + + const patterns = [`integration:${integrationId}:*`, `session-store:${integrationId}`]; + let deletedCount = 0; + for (const pattern of patterns) { + let cursor = "0"; + do { + const [nextCursor, keys] = await client.scan(cursor, "MATCH", pattern, "COUNT", 200); + cursor = nextCursor; + if (keys.length > 0) { + await client.del(...keys); + deletedCount += keys.length; + } + } while (cursor !== "0"); + } + if (deletedCount > 0) { + logger.info("Invalidated integration cache", { integrationId, deletedKeys: deletedCount }); + } +}; + export const createWidgetOptionsChannel = ( widgetKind: WidgetKind, queryKey: string, @@ -385,8 +415,18 @@ export const createChannelWithLatestAndEvents = (channelName: string) => }); }, publishAndUpdateLastStateAsync: async (data: TData) => { - await publisher.publish(channelName, superjson.stringify(data)); - await getSetClient.set(channelName, superjson.stringify({ data, timestamp: new Date() })); + // Set first, then publish. If publish fails the storage is still consistent + // and subscribers will catch up on the next event. + const payload = superjson.stringify({ data, timestamp: new Date() }); + await getSetClient.set(channelName, payload); + try { + await publisher.publish(channelName, superjson.stringify(data)); + } catch (error) { + logger.warn("Failed to publish cache update (storage is correct, subscribers will catch up)", { + channel: channelName, + error: error instanceof Error ? error.message : String(error), + }); + } }, setAsync: async (data: TData) => { await getSetClient.set(channelName, superjson.stringify({ data, timestamp: new Date() })); diff --git a/packages/request-handler/src/beszel.ts b/packages/request-handler/src/beszel.ts index a59309201..6dbe20ae0 100644 --- a/packages/request-handler/src/beszel.ts +++ b/packages/request-handler/src/beszel.ts @@ -1,5 +1,6 @@ import dayjs from "dayjs"; +import { createLogger } from "@homarr/core/infrastructure/logs"; import { createIntegrationAsync } from "@homarr/integrations"; import type { BeszelAlert, @@ -13,6 +14,8 @@ import type { import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler"; +const logger = createLogger({ module: "beszelRequestHandler" }); + export type { BeszelSystemRow } from "@homarr/integrations/types"; /** @@ -56,6 +59,7 @@ export const beszelSystemsRequestHandler = createCachedIntegrationRequestHandler Record >({ async requestAsync(integration) { + const start = performance.now(); const instance = await createIntegrationAsync(integration); const systems = await instance.getSystemsAsync(); const enriched = await Promise.all( @@ -64,9 +68,16 @@ export const beszelSystemsRequestHandler = createCachedIntegrationRequestHandler return mapToSystemRow(system, details); }), ); + logger.debug("beszelSystems fetch completed", { + integrationId: integration.id, + durationMs: Math.round(performance.now() - start), + count: enriched.length, + }); return enriched; }, - cacheDuration: dayjs.duration(5, "seconds"), + cacheDuration: dayjs.duration(1, "second"), + fallbackToStaleOnError: true, + retry: { attempts: 2, delayMs: 500 }, queryKey: "beszelSystems", }); @@ -81,22 +92,31 @@ export const beszelAlertsRequestHandler = createCachedIntegrationRequestHandler< { includeHistory: boolean; maxHistoryItems: number } >({ async requestAsync(integration, input) { + const start = performance.now(); const instance = await createIntegrationAsync(integration); const alerts = await instance.getAlertsAsync(); const history = input.includeHistory ? await instance.getAlertHistoryAsync(undefined, input.maxHistoryItems) : []; + logger.debug("beszelAlerts fetch completed", { + integrationId: integration.id, + durationMs: Math.round(performance.now() - start), + alertsCount: alerts.length, + historyCount: history.length, + }); return { alerts, history }; }, - cacheDuration: dayjs.duration(15, "seconds"), + cacheDuration: dayjs.duration(1, "second"), + fallbackToStaleOnError: true, + retry: { attempts: 2, delayMs: 500 }, queryKey: "beszelAlerts", }); -const timePeriodConfig: Record = { - "1m": { type: "1m", perPage: 60, cacheSeconds: 5 }, - "1h": { type: "1m", perPage: 60, cacheSeconds: 60 }, - "12h": { type: "10m", perPage: 72, cacheSeconds: 300 }, - "24h": { type: "20m", perPage: 72, cacheSeconds: 600 }, - "1w": { type: "120m", perPage: 84, cacheSeconds: 1800 }, - "30d": { type: "480m", perPage: 90, cacheSeconds: 3600 }, +const timePeriodConfig: Record = { + "1m": { type: "1m", perPage: 60 }, + "1h": { type: "1m", perPage: 60 }, + "12h": { type: "10m", perPage: 72 }, + "24h": { type: "20m", perPage: 72 }, + "1w": { type: "480m", perPage: 21 }, + "30d": { type: "480m", perPage: 90 }, }; export interface BeszelStatsData { @@ -110,19 +130,25 @@ export const beszelStatsRequestHandler = createCachedIntegrationRequestHandler< { systemId: string; timePeriod: string; includeDocker: boolean } >({ async requestAsync(integration, input) { - const config = timePeriodConfig[input.timePeriod] ?? { type: "1m", perPage: 60, cacheSeconds: 60 }; + const start = performance.now(); + const config = timePeriodConfig[input.timePeriod] ?? { type: "1m", perPage: 60 }; const instance = await createIntegrationAsync(integration); const systemStats = await instance.getSystemStatsAsync(input.systemId, config.type, config.perPage); const containerStats = input.includeDocker ? await instance.getContainerStatsAsync(input.systemId, config.type, config.perPage).catch(() => []) : []; + logger.debug("beszelStats fetch completed", { + integrationId: integration.id, + systemId: input.systemId, + timePeriod: input.timePeriod, + durationMs: Math.round(performance.now() - start), + systemStatsCount: systemStats.length, + containerStatsCount: containerStats.length, + }); return { systemStats, containerStats }; }, - cacheDuration: dayjs.duration(60, "seconds"), + cacheDuration: dayjs.duration(1, "second"), + fallbackToStaleOnError: true, + retry: { attempts: 2, delayMs: 500 }, queryKey: "beszelStats", - cacheDurationForInput(input) { - const config = timePeriodConfig[input.timePeriod]; - if (!config) return undefined; - return dayjs.duration(config.cacheSeconds, "seconds"); - }, }); diff --git a/packages/request-handler/src/lib/cached-integration-request-handler.ts b/packages/request-handler/src/lib/cached-integration-request-handler.ts index 8c26fcbe6..aee69e39c 100644 --- a/packages/request-handler/src/lib/cached-integration-request-handler.ts +++ b/packages/request-handler/src/lib/cached-integration-request-handler.ts @@ -18,6 +18,9 @@ interface Options, input: TInput) => Promise; cacheDuration: Duration; cacheDurationForInput?: (input: TInput) => Duration | undefined; + fallbackToStaleOnError?: boolean; + retry?: { attempts?: number; delayMs?: number }; + isValid?: (data: TData) => boolean; } export const createCachedIntegrationRequestHandler = < @@ -35,6 +38,9 @@ export const createCachedIntegrationRequestHandler = < return await options.requestAsync(input.integration, input.options); }, cacheDuration: options.cacheDurationForInput?.(itemOptions) ?? options.cacheDuration, + fallbackToStaleOnError: options.fallbackToStaleOnError, + retry: options.retry, + isValid: options.isValid, createRedisChannel(input, handlerOptions) { return createIntegrationOptionsChannel(input.integration.id, handlerOptions.queryKey, input.options); }, diff --git a/packages/request-handler/src/lib/cached-request-handler.ts b/packages/request-handler/src/lib/cached-request-handler.ts index 975448914..c2342eed3 100644 --- a/packages/request-handler/src/lib/cached-request-handler.ts +++ b/packages/request-handler/src/lib/cached-request-handler.ts @@ -7,6 +7,16 @@ import type { createChannelWithLatestAndEvents } from "@homarr/redis"; const logger = createLogger({ module: "cachedRequestHandler" }); +type FetchResult = { data: TData; timestamp: Date }; +type InFlightEntry = Promise>; + +const inFlightFetches = new Map(); + +const isAbortedError = (error: unknown): boolean => { + if (!(error instanceof Error)) return false; + return error.name === "AbortError" || error.name === "TimeoutError"; +}; + interface Options> { // Unique key for this request handler queryKey: string; @@ -17,28 +27,70 @@ interface Options> { ) => ReturnType>; cacheDuration: Duration; fallbackToStaleOnError?: boolean; + // Retry the upstream call on failure. attempts=1 means no retry (default). + // AbortError / TimeoutError are never retried. + retry?: { attempts?: number; delayMs?: number }; + // Predicate to decide whether a fetched response is worth caching. + // Return false to skip the cache write (next call will refetch). + isValid?: (data: TData) => boolean; } +const defaultRetry = { attempts: 1, delayMs: 0 }; +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + export const createCachedRequestHandler = >( options: Options, ) => { return { handler: (input: TInput) => { const channel = options.createRedisChannel(input, options); + const retryConfig = { ...defaultRetry, ...options.retry }; return { async getCachedOrUpdatedDataAsync({ forceUpdate = false }) { const channelData = await channel.getAsync(); - const requestNewDataAsync = async () => { - try { - const data = await options.requestAsync(input); - await channel.publishAndUpdateLastStateAsync(data); - return { - data, - timestamp: new Date(), - }; - } catch (error) { + const requestNewDataAsync = (): Promise> => { + const inflight = inFlightFetches.get(channel.name); + if (inflight) { + logger.debug("Cached request handler joining in-flight fetch", { + channel: channel.name, + queryKey: options.queryKey, + }); + return inflight as Promise>; + } + + const promise = (async (): Promise> => { + let lastError: unknown; + for (let attempt = 1; attempt <= retryConfig.attempts; attempt++) { + try { + const data = await options.requestAsync(input); + if (options.isValid && !options.isValid(data)) { + logger.warn("Cached request handler received invalid data, not caching", { + channel: channel.name, + queryKey: options.queryKey, + attempt, + }); + return { data, timestamp: new Date() }; + } + await channel.publishAndUpdateLastStateAsync(data); + return { data, timestamp: new Date() }; + } catch (error) { + lastError = error; + if (isAbortedError(error) || attempt === retryConfig.attempts) { + break; + } + logger.warn("Cached request handler fetch failed, retrying", { + channel: channel.name, + queryKey: options.queryKey, + attempt, + nextDelayMs: retryConfig.delayMs, + error: error instanceof Error ? `${error.name}: ${error.message}` : String(error), + }); + await sleep(retryConfig.delayMs); + } + } + if (options.fallbackToStaleOnError && channelData) { logger.warn( new ErrorWithMetadata( @@ -46,15 +98,21 @@ export const createCachedRequestHandler = { + inFlightFetches.delete(channel.name); + }); + + inFlightFetches.set(channel.name, promise as InFlightEntry); + return promise; }; if (forceUpdate) { diff --git a/packages/request-handler/src/vpn.ts b/packages/request-handler/src/vpn.ts new file mode 100644 index 000000000..de068938c --- /dev/null +++ b/packages/request-handler/src/vpn.ts @@ -0,0 +1,35 @@ +import dayjs from "dayjs"; + +import { createLogger } from "@homarr/core/infrastructure/logs"; +import type { IntegrationKindByCategory } from "@homarr/definitions"; +import { createIntegrationAsync } from "@homarr/integrations"; +import type { VpnSummary } from "@homarr/integrations/types"; + +import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler"; + +const logger = createLogger({ module: "vpnRequestHandler" }); + +export const vpnSummaryHandler = createCachedIntegrationRequestHandler< + VpnSummary | null, + IntegrationKindByCategory<"vpn">, + Record +>({ + async requestAsync(integration, _input) { + try { + const integrationInstance = await createIntegrationAsync(integration); + return await integrationInstance.getSummaryAsync(); + } catch (error) { + // The VPN control server is unreachable (e.g. the container is down). + // Return null so the widget can render an "unavailable" status instead of + // surfacing a hard error, and so it recovers automatically once it is back up. + logger.warn("Failed to fetch VPN summary, marking as unavailable", { + integrationId: integration.id, + integrationKind: integration.kind, + error: error instanceof Error ? error.message : String(error), + }); + return null; + } + }, + cacheDuration: dayjs.duration(5, "minutes"), + queryKey: "vpnSummary", +}); diff --git a/packages/translation/src/lang/ca.json b/packages/translation/src/lang/ca.json index d9f8c3d6d..18d07473d 100644 --- a/packages/translation/src/lang/ca.json +++ b/packages/translation/src/lang/ca.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/cn.json b/packages/translation/src/lang/cn.json index dabce6706..04f93c6b9 100644 --- a/packages/translation/src/lang/cn.json +++ b/packages/translation/src/lang/cn.json @@ -4415,18 +4415,6 @@ "general": { "title": "发送匿名分析", "text": "Homarr 将使用开源软件 Umami 发送匿名分析数据。启用后,我们会收集:Homarr 版本、数据库类型(MySQL/PostgreSQL/SQLite)、Docker/Kubernetes 状态、已启用的身份验证方法以及各项功能的数量。所有数据均为匿名且汇总收集——绝不收集任何个人信息、URL、名称或可识别数据。这有助于我们的开源团队了解使用模式并确定开发优先级。" - }, - "widgetData": { - "title": "组件数据", - "text": "发送您已配置的组件(及其数量)。不包括URL、名称或任何其他数据。" - }, - "integrationData": { - "title": "集成数据", - "text": "发送您已配置的集成(及其数量)。不包括URL、名称或任何其他数据。" - }, - "usersData": { - "title": "用户数据", - "text": "发送用户数量以及您是否激活了SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "已更新 {when}", "search": "搜索 {count} 容器", "selected": "{totalCount} 容器的 {selectCount}", - "footer": "总计 {count} 容器" + "footer": "总计 {count} 容器", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/cr.json b/packages/translation/src/lang/cr.json index ad7f1528a..9341366dc 100644 --- a/packages/translation/src/lang/cr.json +++ b/packages/translation/src/lang/cr.json @@ -4413,20 +4413,8 @@ "analytics": { "title": "crwdns1764:0crwdne1764:0", "general": { - "title": "crwdns1766:0crwdne1766:0", - "text": "crwdns3878:0crwdne3878:0" - }, - "widgetData": { - "title": "crwdns1770:0crwdne1770:0", - "text": "crwdns1772:0crwdne1772:0" - }, - "integrationData": { - "title": "crwdns1774:0crwdne1774:0", - "text": "crwdns1776:0crwdne1776:0" - }, - "usersData": { - "title": "crwdns1778:0crwdne1778:0", - "text": "crwdns1780:0crwdne1780:0" + "title": "crwdns5673:0crwdne5673:0", + "text": "crwdns5675:0crwdne5675:0" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "crwdns1894:0{when}crwdne1894:0", "search": "crwdns3432:0{count}crwdne3432:0", "selected": "crwdns1898:0{selectCount}crwdnd1898:0{totalCount}crwdne1898:0", - "footer": "crwdns3434:0{count}crwdne3434:0" + "footer": "crwdns3434:0{count}crwdne3434:0", + "totalCpu": "crwdns5669:0{cpu}crwdne5669:0", + "totalMemory": "crwdns5671:0{memory}crwdne5671:0" }, "field": { "name": { diff --git a/packages/translation/src/lang/cs.json b/packages/translation/src/lang/cs.json index 19bca773a..89b8949bb 100644 --- a/packages/translation/src/lang/cs.json +++ b/packages/translation/src/lang/cs.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "Uživatelská data", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/da.json b/packages/translation/src/lang/da.json index 307f2cdbe..d22ef9c61 100644 --- a/packages/translation/src/lang/da.json +++ b/packages/translation/src/lang/da.json @@ -4415,18 +4415,6 @@ "general": { "title": "Indsend anonyme analysedata", "text": "Homarr vil sende anonymiserede analyser ved hjælp af open source-softwaren Umami. Den indsamler aldrig personlige oplysninger og er derfor fuldt ud GDPR & CCPA kompatibel. Vi opfordrer dig til at aktivere analyser, fordi det hjælper vores open source-team til at identificere problemer og prioritere vores backlog." - }, - "widgetData": { - "title": "Widget data", - "text": "Send hvilke widgets (og deres antal) du har konfigureret. Indeholder ikke URL'er, navne eller andre data." - }, - "integrationData": { - "title": "Integrationsdata", - "text": "Send hvilke integrationer (og deres antal) du har konfigureret. Indeholder ikke URL'er, navne eller andre data." - }, - "usersData": { - "title": "Brugerdata", - "text": "Send mængden af brugere, og om du har aktiveret SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Opdateret {when}", "search": "Søg {count} containere", "selected": "{selectCount} af {totalCount} containere valgt", - "footer": "Total {count} containere" + "footer": "Total {count} containere", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/de-CH.json b/packages/translation/src/lang/de-CH.json index a9d814e3b..bbe34e1c0 100644 --- a/packages/translation/src/lang/de-CH.json +++ b/packages/translation/src/lang/de-CH.json @@ -4415,18 +4415,6 @@ "general": { "title": "Anonymisierte Nutzungsdaten senden", "text": "Homarr schickt anonymisierte Nutzungsdaten mit der Open-Source-Software Umami. Es sammelt zu keinem Zeitpunkt personenbezogene Daten und ist daher vollständig DPR & CCPA konform. Wir empfehlen diese Nutzungsdaten zu aktivieren, da es unserem Open-Source-Team hilft Probleme zu identifizieren und unserem Backlog ermöglicht Priorität einzuräumen." - }, - "widgetData": { - "title": "Widget Daten", - "text": "Senden Sie die Widgets (und deren Anzahl) die Sie konfiguriert haben. Enthält keine URLs, Namen oder andere Daten." - }, - "integrationData": { - "title": "Integrationsdaten", - "text": "Senden Sie die Intregrationen (und deren Anzahl) die Sie konfiguriert haben. Enthält keine URLs, Namen oder andere Daten." - }, - "usersData": { - "title": "Benutzerdaten", - "text": "Senden Sie die Anzahl der Benutzer und ob Sie SSO aktiviert haben" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Aktualisiert {when}", "search": "{count} Container durchsuchen", "selected": "{selectCount} von {totalCount} ausgewählten Containern", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/de.json b/packages/translation/src/lang/de.json index 2d1730a83..09d4a4ce2 100644 --- a/packages/translation/src/lang/de.json +++ b/packages/translation/src/lang/de.json @@ -3374,27 +3374,27 @@ "pausedCount": "Pausiert" }, "error": { - "internalServerError": "" + "internalServerError": "Fehler beim Abrufen der Laufzeit Daten" } }, "audioStats": { "name": "Audiostatistiken", - "description": "", + "description": "Bibliotheks- und Wiedergabestatistiken von Navidrome oder Audiobookshelf", "option": { "showArtists": { "label": "Künstler anzeigen", - "description": "" + "description": "Zeige die Gesamtzahl der Künstler in deiner Musikbibliothek (Navidrome)" }, "showAlbums": { - "label": "", + "label": "Alben anzeigen", "description": "Zeigt die Gesamtzahl der Alben in deiner Musikbibliothek an (Navidrome)" }, "showSongs": { "label": "Songs anzeigen", - "description": "" + "description": "Zeigt die Gesamtzahl der Titel in deiner Musikbibliothek an (Navidrome)" }, "showNowPlaying": { - "label": "", + "label": "\"Sie hören\" anzeigen", "description": "" }, "showNowPlayingList": { @@ -3720,7 +3720,7 @@ }, "chart": { "cpu": { - "title": "CPU-Auslastung", + "title": "CPU Auslastung", "subtitle": "", "series": "CPU" }, @@ -4415,18 +4415,6 @@ "general": { "title": "Anonymisierte Nutzungsdaten senden", "text": "Homarr sendet anonymisierte Analysen mit der Open-Source-Software Umami. Wenn aktiviert, sammeln wir die Homarr-Version, den Datenbanktyp (MySQL/PostgreSQL/SQLite), den Docker/Kubernetes Status, die Authentifizierungsmethoden und die Anzahl der einzelnen Features. Alle Daten sind anonym und aggregiert - es werden keine persönlichen Informationen, URLs, Namen oder identifizierbare Daten gesammelt. Dies hilft unserem Open-Source-Team, Nutzungsmuster zu verstehen und der Entwicklung Priorität einzuräumen." - }, - "widgetData": { - "title": "Widget Daten", - "text": "Senden Sie die Widgets (und deren Anzahl) die Sie konfiguriert haben. Enthält keine URLs, Namen oder andere Daten." - }, - "integrationData": { - "title": "Integrationsdaten", - "text": "Senden Sie die Intregrationen (und deren Anzahl) die Sie konfiguriert haben. Enthält keine URLs, Namen oder andere Daten." - }, - "usersData": { - "title": "Benutzerdaten", - "text": "Senden Sie die Anzahl der Benutzer und ob Sie SSO aktiviert haben" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Aktualisiert {when}", "search": "{count} Container durchsuchen", "selected": "{selectCount} von {totalCount} ausgewählten Containern", - "footer": "Insgesamt {count} Container" + "footer": "Insgesamt {count} Container", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/el.json b/packages/translation/src/lang/el.json index 6e715e372..168501668 100644 --- a/packages/translation/src/lang/el.json +++ b/packages/translation/src/lang/el.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/en-gb.json b/packages/translation/src/lang/en-gb.json index b743ead49..ff08eecf7 100644 --- a/packages/translation/src/lang/en-gb.json +++ b/packages/translation/src/lang/en-gb.json @@ -177,7 +177,7 @@ }, "password": { "label": "Password", - "suggestionsTitle": "", + "suggestionsTitle": "Password suggestions", "suggestion": { "length": "Includes a minimum of 8 characters", "lowercase": "Includes a lower-case letter", @@ -687,28 +687,28 @@ "customWidget": { "page": { "list": { - "title": "", - "noResults": "", - "loading": "" + "title": "Custom Widgets", + "noResults": "No custom widgets yet. Create your first one!", + "loading": "Loading..." }, "create": { - "title": "", - "subtitle": "" + "title": "Create Custom Widget", + "subtitle": "Define an API URL, authentication, and how to display the response data." }, "edit": { - "title": "" + "title": "Edit Custom Widget" } }, "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", + "create": "Create", + "import": "Import", + "save": "Save", + "delete": "Delete Custom Widget", + "deleteConfirm": "Are you sure you want to delete \"{name}\"? This action cannot be undone.", + "export": "Export", + "addMapping": "Add Mapping", + "addColumn": "Add Column", + "edit": "Edit", "removeMapping": "", "removeColumn": "", "addItem": "", @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { @@ -5609,71 +5599,71 @@ "label": "", "children": { "detail": { - "title": "" + "title": "Select your colour scheme" } } }, "locale": { - "label": "", + "label": "Language", "children": { "detail": { - "title": "" + "title": "Select your preferred language" } } }, "defaultSearchEngineId": { - "label": "", + "label": "Default search engine", "children": { "detail": { - "title": "" + "title": "Select your default search engine" } } }, "openSearchInNewTab": { - "label": "", + "label": "Open search results in new tab", "children": { "detail": { - "title": "" + "title": "Open search results in new tab" } } }, "ddgBangs": { - "label": "", + "label": "Enable DuckDuckGo bangs", "children": { "detail": { - "title": "" + "title": "Enable DuckDuckGo bangs" } } }, "firstDayOfWeek": { - "label": "", + "label": "First day of the week", "children": { "detail": { - "title": "" + "title": "Select the first day of the week" } } }, "homeBoardId": { - "label": "", + "label": "Home board", "children": { "detail": { - "title": "" + "title": "Select your home board" } } }, "mobileHomeBoardId": { - "label": "", + "label": "Mobile home board", "children": { "detail": { - "title": "" + "title": "Select your mobile home board" } } }, "pingIconsEnabled": { - "label": "", + "label": "Use icons for pings", "children": { "detail": { - "title": "" + "title": "Use icons for pings" } } }, diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 7bb00c5f0..190a13733 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1021,6 +1021,7 @@ "mediaMonitoring": "Monitoring", "speedtest": "Speed Test", "analytics": "Analytics", + "vpn": "VPN", "mediaLibrary": "Media Library", "uptimeMonitoring": "Uptime Monitoring" }, @@ -1412,7 +1413,10 @@ "here": "here", "iconPicker": { "label": "Icon URL", - "header": "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you." + "header": "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you.", + "headerLoading": "Type to search icons…", + "noResults": "No icons match \"{search}\".", + "error": "Couldn't load icons." }, "colorScheme": { "options": { @@ -1464,6 +1468,7 @@ "switchToDarkMode": "Switch to dark mode", "switchToLightMode": "Switch to light mode", "management": "Management", + "docker": "Docker", "preferences": "Your preferences", "logout": "Logout", "login": "Login", @@ -2405,6 +2410,12 @@ "title": "Instances" } }, + "vpn": { + "name": "VPN", + "description": "Overview of your VPN connections", + "serviceUnavailable": "VPN unavailable", + "option": {} + }, "ups": { "name": "UPS", "description": "Monitor the status of your UPS devices through a NUT server", @@ -3639,6 +3650,9 @@ "error": { "internalServerError": "Unable to connect to Beszel. Check your integration settings." }, + "empty": { + "noSystems": "No systems found" + }, "metric": { "cpu": "CPU", "memory": "Memory", @@ -3712,6 +3726,9 @@ } }, "selectSystem": "Select system", + "empty": { + "noSystems": "No systems found" + }, "error": { "internalServerError": "Unable to connect to Beszel. Check your integration settings.", "liveConnectionFailed": "Live connection failed. Your Beszel instance may not support real-time streaming.", @@ -4133,6 +4150,11 @@ "title": "Not Found", "text": "Could not find requested resource" }, + "error": { + "title": "This page couldn't load", + "text": "An unexpected error occurred while loading this page. Your navigation is still available — try reloading, or use another section from the sidebar.", + "digest": "Error reference: {digest}" + }, "navbar": { "items": { "home": "Home", @@ -4286,7 +4308,7 @@ "notStarted": "Not started" }, "name": { - "management": "Management", +"management": "Management", "dashboard": "Dashboard" } } @@ -4579,6 +4601,9 @@ }, "umamiActiveVisitors": { "label": "Umami Active Visitors" + }, + "vpn": { + "label": "VPN Status" } }, "interval": { diff --git a/packages/translation/src/lang/es.json b/packages/translation/src/lang/es.json index 5df897416..7858cc262 100644 --- a/packages/translation/src/lang/es.json +++ b/packages/translation/src/lang/es.json @@ -4415,18 +4415,6 @@ "general": { "title": "Enviar estadísticas anónimas", "text": "Homarr enviará estadísticas anónimas usando el software de código abierto Umami. Nunca recopila información personal y por lo tanto cumple plenamente con GDPR y CCPA. Te animamos a habilitar esta característica ya que ayuda a nuestro equipo de código abierto a identificar problemas y priorizar su resolución." - }, - "widgetData": { - "title": "Datos del widget", - "text": "Enviar qué widgets (y su cantidad) has configurado. No incluye URLs, nombres ni ningún otro dato." - }, - "integrationData": { - "title": "Datos de integración", - "text": "Enviar qué integraciones (y su cantidad) has configurado. No incluye URLs, nombres ni ningún otro dato." - }, - "usersData": { - "title": "Datos de usuarios", - "text": "Enviar la cantidad de usuarios y si has activado SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Actualizado {when}", "search": "Buscar {count} contenedores", "selected": "{selectCount} de {totalCount} contenedores seleccionados", - "footer": "{count} contenedores en total" + "footer": "{count} contenedores en total", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/et.json b/packages/translation/src/lang/et.json index 6b6beda7f..606d4833f 100644 --- a/packages/translation/src/lang/et.json +++ b/packages/translation/src/lang/et.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/fi.json b/packages/translation/src/lang/fi.json index 1271c5b20..713c729b1 100644 --- a/packages/translation/src/lang/fi.json +++ b/packages/translation/src/lang/fi.json @@ -4415,18 +4415,6 @@ "general": { "title": "Lähetä anonyymejä käyttötietoja", "text": "Homarr lähettää anonymisoitua analytiikkaa avoimen lähdekoodin Umami‑järjestelmän avulla. Kun analytiikka on käytössä, keräämme seuraavat tiedot: Homarrin version, tietokannan tyypin (MySQL/PostgreSQL/SQLite), Docker‑/Kubernetes‑tilan, käytössä olevat tunnistautumismenetelmät sekä eri ominaisuuksien lukumäärät. Kaikki tiedot on anonymisoitu ja koottu tilastomuotoon – mitään henkilötietoja, URL‑osoitteita, nimiä tai muita tunnistettavia tietoja ei koskaan kerätä. Tämä auttaa avoimen lähdekoodin tiimiämme ymmärtämään käyttötapoja ja priorisoimaan kehitystä." - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "Integraatiotiedot", - "text": "Lähetä mitä ja miten monta integraatiota olet määrittänyt. Ei sisällä URL-osoitteita, nimiä tai mitään muita tietoja." - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Päivitetty {when}", "search": "Suodata {count} konttia...", "selected": "{selectCount}/{totalCount} kontista valittu", - "footer": "Yhteensä {count} konttia" + "footer": "Yhteensä {count} konttia", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/fr.json b/packages/translation/src/lang/fr.json index 7aac082c5..25b85fe71 100644 --- a/packages/translation/src/lang/fr.json +++ b/packages/translation/src/lang/fr.json @@ -4415,18 +4415,6 @@ "general": { "title": "Envoyer des statistiques anonymes", "text": "Homarr enverra des statistiques anonymes en utilisant le logiciel open source Umami. Il ne recueille jamais aucune information personnelle et est donc entièrement conforme au RGPD & CCPA. Nous vous encourageons à activer les statistiques parce qu'elles aident notre équipe open source à identifier les problèmes et à prioriser notre backlog." - }, - "widgetData": { - "title": "Données du widget", - "text": "Envoie quels widgets (et leur quantité) vous avez configurés. N'inclut pas les URLs, les noms ou toute autre donnée." - }, - "integrationData": { - "title": "Données d'intégration", - "text": "Envoie quelles intégrations (et leur quantité) vous avez configurées. N'inclut pas les URLs, les noms ou toute autre donnée." - }, - "usersData": { - "title": "Données utilisateur", - "text": "Envoie le nombre d'utilisateurs et si vous avez activé le SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Mis à jour {when}", "search": "Rechercher dans {count} conteneurs", "selected": "{selectCount} sur {totalCount} conteneurs sélectionnés", - "footer": "Total des conteneurs {count}" + "footer": "Total des conteneurs {count}", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/he.json b/packages/translation/src/lang/he.json index a1fc5c8d9..5ecba1a8c 100644 --- a/packages/translation/src/lang/he.json +++ b/packages/translation/src/lang/he.json @@ -4415,18 +4415,6 @@ "general": { "title": "שליחת ניתוח נתונים אנונימי", "text": "Homarr ישלח ניתוחים אנונימיים באמצעות התוכנה בקוד פתוח Umami. הוא לעולם אינו אוסף מידע אישי ולכן תואם לחלוטין לדרישות ה-GDPR וה-CCPA. אנו מעודדים אותך להפעיל ניתוחים, כיוון שזה מסייע לצוות הקוד הפתוח שלנו לזהות בעיות ולהעניק עדיפות למשימות שברשימת העדיפויות שלנו." - }, - "widgetData": { - "title": "נתוני ווידג׳ט", - "text": "שלח אילו ווידג'טים (וכמותם) הוגדרו. אינו כולל כתובות רשת, שמות או כל מידע נוסף אחר." - }, - "integrationData": { - "title": "נתוני אינטגרציה", - "text": "שלח אילו אינטגרציות (וכמותם) הוגדרו. לא כולל כתובות רשת, שמות או כל מידע נוסף אחר." - }, - "usersData": { - "title": "נתוני משתמשים", - "text": "שלח את כמות המשתמשים והאם הופעל SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "עודכן ב- {when}", "search": "חפש {count} קונטיינרים", "selected": "{selectCount} מ- {totalCount} קונטיינרים נבחרו", - "footer": "סה״כ {count} קונטיינרים" + "footer": "סה״כ {count} קונטיינרים", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/hr.json b/packages/translation/src/lang/hr.json index 36ff0ecf8..1f7d5013b 100644 --- a/packages/translation/src/lang/hr.json +++ b/packages/translation/src/lang/hr.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/hu.json b/packages/translation/src/lang/hu.json index 57325e118..1c8d473d7 100644 --- a/packages/translation/src/lang/hu.json +++ b/packages/translation/src/lang/hu.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "A Homarr az Umami nevű nyílt forráskódú szoftver segítségével névtelen elemzési adatokat küld. Ha ez az opció engedélyezve van, a következő adatokat gyűjtjük: a Homarr verziója, az adatbázis típusa (MySQL/PostgreSQL/SQLite), a Docker/Kubernetes állapota, az engedélyezett hitelesítési módszerek, valamint az egyes funkciók száma. Minden adat névtelen és összesített formában kerül rögzítésre – személyes adatokat, URL-eket, neveket vagy bármilyen azonosítható adatot soha nem gyűjtünk. Ez segít nyílt forráskódú fejlesztői csapatunknak a használati szokások megértésében és a fejlesztési feladatok fontossági sorrendjének meghatározásában." - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/it.json b/packages/translation/src/lang/it.json index 0f8ae0634..e170a2565 100644 --- a/packages/translation/src/lang/it.json +++ b/packages/translation/src/lang/it.json @@ -4415,18 +4415,6 @@ "general": { "title": "Invia analytics anonimi", "text": "Homarr invierà analisi anonime utilizzando il software open source Umami. Non raccoglie mai informazioni personali ed è quindi pienamente conforme al GDPR e al CCPA. Ti invitiamo ad abilitare l'analisi perché aiuta il nostro team open source a identificare i problemi e a dare priorità al nostro arretrato." - }, - "widgetData": { - "title": "Dati widget", - "text": "Invia quali widget (e la loro quantità) hai configurato. Non include URL, nomi o altri dati." - }, - "integrationData": { - "title": "Dati di integrazione", - "text": "Invia quali integrazioni (e la loro quantità) hai configurato. Non include URL, nomi o altri dati." - }, - "usersData": { - "title": "Dati utenti", - "text": "Invia il numero di utenti e se hai attivato SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Aggiornato {when}", "search": "Cerca {count} container", "selected": "{selectCount} di {totalCount} containers selezionati", - "footer": "Totale container {count}" + "footer": "Totale container {count}", + "totalCpu": "CPU Totale: {cpu}%", + "totalMemory": "Mem Totale: {memory}" }, "field": { "name": { diff --git a/packages/translation/src/lang/ja.json b/packages/translation/src/lang/ja.json index f58996caf..1be05e8c8 100644 --- a/packages/translation/src/lang/ja.json +++ b/packages/translation/src/lang/ja.json @@ -4415,18 +4415,6 @@ "general": { "title": "匿名の解析を送信", "text": "Homarrは、オープンソースソフトウェアUmamiを使用して匿名化された分析を送信します。 有効にすると、以下が収集されます。Homarrバージョン、データベースタイプ(MySQL/PostgreSQL/SQLite)、Docker/Kubernetesステータス、認証方法、各機能の数。 すべてのデータは匿名で集計されます。個人情報、URL、名前、または識別可能なデータは収集されません。 これにより、オープンソースチームは利用パターンを理解し、開発に優先順位を付けることができます。" - }, - "widgetData": { - "title": "ウィジェットのデータ", - "text": "あなたが設定したウィジェット(およびその数量)を送信します。URL・名前・その他のデータは含まれません。" - }, - "integrationData": { - "title": "連携情報", - "text": "あなたが設定した連携機能(およびその数量)を送信します。URL・名前・その他のデータは含まれません。" - }, - "usersData": { - "title": "ユーザー情報", - "text": "SSOをアクティベートしたユーザーの数を送信します" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "{when} に更新しました", "search": "{count} 個のコンテナを検索", "selected": "{totalCount} 個のうち、{selectCount} 個のコンテナが選択されています", - "footer": "合計 {count} 個のコンテナ" + "footer": "合計 {count} 個のコンテナ", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/ko.json b/packages/translation/src/lang/ko.json index 8bde1c696..8ddf946f3 100644 --- a/packages/translation/src/lang/ko.json +++ b/packages/translation/src/lang/ko.json @@ -214,20 +214,20 @@ "action": { "login": { "label": "로그인", - "labelWith": "", + "labelWith": "{provider}(으)로 로그인", "notification": { "success": { - "title": "", - "message": "" + "title": "로그인 성공", + "message": "현재 로그인되어 있음" }, "error": { - "title": "", - "message": "" + "title": "로그인 실패", + "message": "당신의 로그인이 실패했습니다" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "비밀번호를 잊으셨습니까?", + "description": "관리자는 다음 명령을 사용해 비밀번호를 재설정할 수 있습니다:" } }, "register": { @@ -235,53 +235,53 @@ "notification": { "success": { "title": "계정 생성", - "message": "" + "message": "계속하려면 로그인하십시오" }, "error": { - "title": "", - "message": "" + "title": "계정 생성 실패", + "message": "당신의 계정을 생성하지 못했습니다" } } }, "create": "사용자 만들기", "changePassword": { - "label": "", + "label": "패스워드 변경", "notification": { "success": { - "message": "" + "message": "패스워드 변경 완료" }, "error": { - "message": "" + "message": "패스워드를 변경할 수 없습니다" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "홈 보드 변경 완료" }, "error": { - "message": "" + "message": "홈 보드를 변경할 수 없습니다" } } }, "changeSearchPreferences": { "notification": { "success": { - "message": "" + "message": "검색 설정 변경 완료" }, "error": { - "message": "" + "message": "검색 설정을 변경할 수 없습니다" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "주 시작 요일 변경 완료" }, "error": { - "message": "" + "message": "주 시작 요일을 변경할 수 없습니다" } } }, @@ -298,38 +298,38 @@ "changeDdgBangs": { "notification": { "success": { - "message": "" + "message": "DuckDuckGo bangs 전환 완료" }, "error": { - "message": "" + "message": "DuckDuckGo bangs 전환 실패" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "이미지 변경", "notification": { "success": { - "message": "" + "message": "이미지 변경 완료" }, "error": { - "message": "" + "message": "이미지를 변경할 수 없습니다" }, "toLarge": { - "title": "", - "message": "" + "title": "이미지가 너무 큽니다", + "message": "이미지 최대 크기는 {size}입니다" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "이미지 제거", + "confirm": "이미지를 제거하시겠습니까?", "notification": { "success": { - "message": "" + "message": "이미지 제거 완료" }, "error": { - "message": "" + "message": "이미지를 제거할 수 없습니다" } } } @@ -337,7 +337,7 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "프로필 업데이트 완료" }, "error": { "message": "프로필을 업데이트할 수 없습니다" @@ -346,8 +346,8 @@ }, "delete": { "label": "사용자 영원히 삭제", - "description": "", - "confirm": "" + "description": "이 사용자와 설정을 삭제합니다. 보드는 삭제되지 않습니다. 사용자에게 알려지지 않습니다.", + "confirm": "사용자 {username}와(과) 설정을 삭제하시겠습니까?" }, "select": { "label": "사용자 선택", @@ -367,11 +367,11 @@ "members": "멤버", "homeBoard": { "label": "홈 보드", - "description": "" + "description": "그룹이 접근할 수 있는 보드만 선택할 수 있습니다" }, "mobileBoard": { "label": "모바일 보드", - "description": "" + "description": "그룹이 접근할 수 있는 보드만 선택할 수 있습니다" } }, "permission": { @@ -393,15 +393,15 @@ }, "use-all": { "label": "모든 앱 사용", - "description": "" + "description": "멤버가 보드에 앱을 추가할 수 있도록 허용" }, "modify-all": { - "label": "", - "description": "" + "label": "모든 앱 수정", + "description": "멤버가 모든 앱을 수정할 수 있도록 허용" }, "full-all": { - "label": "", - "description": "" + "label": "전체 앱 접근", + "description": "멤버가 모든 앱을 관리, 사용 및 삭제할 수 있도록 허용" } } }, @@ -409,20 +409,20 @@ "title": "보드", "item": { "create": { - "label": "", - "description": "" + "label": "보드 생성", + "description": "멤버가 보드를 생성할 수 있도록 허용" }, "view-all": { - "label": "", - "description": "" + "label": "모든 보드 보기", + "description": "멤버가 모든 보드를 볼 수 있도록 허용" }, "modify-all": { - "label": "", - "description": "" + "label": "모든 보드 수정", + "description": "멤버가 모든 보드를 수정할 수 있도록 허용 (접근 제어 및 위험 항목은 포함되지 않음)" }, "full-all": { - "label": "", - "description": "" + "label": "전체 보드 접근", + "description": "멤버가 모든 보드를 열람, 수정 및 삭제할 수 있도록 허용 (접근 제어 및 위험 항목 포함)" } } }, @@ -438,147 +438,147 @@ "description": "멤버의 보드에 통합을 추가하는 것을 허용합니다" }, "interact-all": { - "label": "", - "description": "" + "label": "모든 통합과 상호작용", + "description": "멤버가 모든 통합과 상호작용할 수 있도록 허용합니다" }, "full-all": { - "label": "", - "description": "" + "label": "전체 통합 접근", + "description": "멤버가 모든 통합을 관리, 사용 및 상호작용할 수 있도록 허용합니다" } } }, "media": { - "title": "", + "title": "미디어", "item": { "upload": { - "label": "", - "description": "" + "label": "미디어 업로드", + "description": "멤버가 미디어 파일을 업로드할 수 있도록 허용합니다" }, "view-all": { - "label": "", - "description": "" + "label": "모든 미디어 열람", + "description": "멤버가 모든 미디어를 열람할 수 있도록 허용합니다" }, "full-all": { - "label": "", - "description": "" + "label": "전체 미디어 접근", + "description": "멤버가 모든 미디어를 관리 및 삭제할 수 있도록 허용합니다" } } }, "other": { - "title": "", + "title": "기타", "item": { "view-logs": { - "label": "", - "description": "" + "label": "로그 조회", + "description": "멤버가 로그를 조회할 수 있도록 허용합니다" } } }, "search-engine": { - "title": "", + "title": "검색 엔진", "item": { "create": { - "label": "", - "description": "" + "label": "검색 엔진 생성", + "description": "멤버가 검색 엔진을 생성할 수 있도록 허용합니다" }, "modify-all": { - "label": "", - "description": "" + "label": "모든 검색 엔진 수정", + "description": "멤버가 모든 검색 엔진을 수정할 수 있도록 허용합니다" }, "full-all": { - "label": "", - "description": "" + "label": "전체 검색 엔진 접근", + "description": "멤버가 모든 검색 엔진을 관리 및 삭제할 수 있도록 허용합니다" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "일부 멤버는 외부 제공자에서 유래하여 여기서 관리할 수 없습니다", + "external": "모든 멤버가 외부 제공자에서 유래하여 여기서 관리할 수 없습니다" }, "reservedNotice": { - "message": "" + "message": "이 그룹은 시스템 사용을 위해 예약되어 일부 작업을 제한합니다. " }, "action": { "create": { - "label": "", + "label": "새 그룹", "notification": { "success": { - "message": "" + "message": "그룹 생성이 완료되었습니다" }, "error": { - "message": "" + "message": "그룹 생성에 실패했습니다" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "소유권 이전", + "description": "이 그룹의 소유권을 다른 사용자에게 이전합니다.", + "confirm": "{name} 그룹 소유권을 {username}에게 이전하시겠습니까?", "notification": { "success": { - "message": "" + "message": "{user}에게 {group} 그룹 이전 완료" }, "error": { - "message": "" + "message": "소유권을 이전할 수 없습니다" } } }, "addMember": { - "label": "" + "label": "멤버 추가" }, "removeMember": { - "label": "", - "confirm": "" + "label": "멤버 제거", + "confirm": "{user} 사용자를 이 그룹에서 제거하시겠습니까?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "그룹 삭제", + "description": "그룹을 삭제하면 되돌릴 수 없습니다. 다시 한 번 확인해 주십시오.", + "confirm": "{name} 그룹을 삭제하시겠습니까?", "notification": { "success": { - "message": "" + "message": "{name} 그룹 삭제 완료" }, "error": { - "message": "" + "message": "{name} 그룹을 삭제할 수 없습니다" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "권한 저장됨", + "message": "권한 저장 완료" }, "error": { - "title": "", - "message": "" + "title": "권한 저장되지 않음", + "message": "권한이 저장되지 않았습니다" } } }, "update": { "notification": { "success": { - "message": "" + "message": "{name} 그룹 저장 완료" }, "error": { - "message": "" + "message": "{name} 그룹을 저장할 수 없습니다" } } }, "select": { - "label": "", - "notFound": "" + "label": "그룹 선택", + "notFound": "그룹 없음" }, "settings": { "board": { "notification": { "success": { - "title": "", - "message": "" + "title": "설정 저장됨", + "message": "보드 설정 저장 완료" }, "error": { - "title": "", - "message": "" + "title": "설정 저장 실패", + "message": "보드 설정을 저장할 수 없습니다" } } } @@ -586,66 +586,66 @@ "changePosition": { "notification": { "success": { - "message": "" + "message": "위치 변경 완료" }, "error": { - "message": "" + "message": "위치를 변경할 수 없습니다" } } } }, "defaultGroup": { - "name": "", - "description": "" + "name": "기본 그룹", + "description": "{name} - 모든 로그인 사용자" } }, "app": { - "search": "", + "search": "앱 찾기", "page": { "list": { "title": "앱", "noResults": { - "title": "", - "action": "" + "title": "아직 앱이 없습니다", + "action": "첫 번째 앱 만들기" } }, "create": { - "title": "", + "title": "새 앱", "notification": { "success": { - "title": "", - "message": "" + "title": "생성 완료", + "message": "앱 생성이 완료되었습니다" }, "error": { - "title": "", - "message": "" + "title": "생성 실패", + "message": "앱 생성에 실패했습니다" } } }, "edit": { - "title": "", + "title": "앱 편집", "notification": { "success": { - "title": "", - "message": "" + "title": "변경 사항 적용 완료", + "message": "앱 설정 저장이 완료되었습니다" }, "error": { - "title": "", - "message": "" + "title": "변경 사항 적용 실패", + "message": "앱 설정 저장에 실패했습니다" } } }, "delete": { - "title": "", - "message": "", + "title": "앱 삭제", + "message": "{name} 앱을 삭제하시겠습니까?", "notification": { "success": { - "title": "", - "message": "" + "title": "삭제 완료", + "message": "앱 삭제가 완료되었습니다" }, "error": { - "title": "", - "message": "" + "title": "삭제 실패", + "message": "앱을 삭제할 수 없습니다" } } } @@ -655,52 +655,52 @@ "label": "이름" }, "description": { - "label": "" + "label": "설명" }, "url": { - "label": "" + "label": "URL" }, "useDifferentUrlForPing": { "checkbox": { - "label": "", - "description": "" + "label": "다른 URL을 ping에 사용", + "description": "ISP 대역폭 사용을 피하기 위해 Homarr가 내부 호스트네임 또는 네트워크를 사용하여 직접 접근할 수 있는 경우에 유용합니다" } } }, "action": { "select": { - "label": "", - "notFound": "", - "search": "", - "noResults": "", - "action": "", - "title": "" + "label": "앱 선택", + "notFound": "앱 없음", + "search": "앱 검색", + "noResults": "결과 없음", + "action": "{app} 선택", + "title": "이 보드에 추가할 앱 선택" }, "create": { - "title": "", - "description": "", - "action": "" + "title": "새 앱 생성", + "description": "새 앱 생성 ", + "action": "앱 생성 열기" }, - "add": "" + "add": "앱 추가" } }, "customWidget": { "page": { "list": { - "title": "", - "noResults": "", - "loading": "" + "title": "사용자 지정 위젯", + "noResults": "사용자 지정 위젯이 아직 없습니다. 첫 위젯을 만들어 보세요!", + "loading": "불러오는 중..." }, "create": { - "title": "", - "subtitle": "" + "title": "사용자 지정 위젯 생성", + "subtitle": "API URL, 인증, 응답 데이터 표시 방식을 정의합니다." }, "edit": { - "title": "" + "title": "사용자 지정 위젯 편집" } }, "action": { - "create": "", + "create": "생성", "import": "", "save": "", "delete": "", @@ -751,36 +751,36 @@ "dotSize": "", "valueSize": "", "labelPosition": "", - "kvLayout": "", + "kvLayout": "레이아웃", "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", + "compact": "컴팩트 모드", + "maxHeight": "최대 높이 (px)", + "color": "색상", + "buttonLabel": "버튼 명칭", + "buttonColor": "버튼 색상", + "confirmText": "확인 텍스트", + "confirmTextHint": "설정하면 요청을 실행하기 전에 확인 대화상자가 표시됩니다", + "successMessage": "성공 메세지", + "successMessageHint": "실행 성공 후 표시되는 메세지", + "enabled": "활성화됨", "template": { - "label": "", + "label": "JSX 템플릿", "description": "" } }, "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", + "exampleLabel": "CPU 온도", + "exampleLabelShort": "CPU 온도", + "exampleHeader": "이름", + "exampleUnit": "°C", + "iconUrl": "https://...", + "url": "https://api.example.com/api/v1/status", + "headerName": "X-API-Key", + "jsonPath": "$.data.value", + "tablePath": "$.data.items", + "columnJsonPath": "$.name", + "valuePath": "$.data.used", + "maxPath": "$.data.total", "goodValues": "", "color": "" }, @@ -859,34 +859,34 @@ "rawResponse": "" }, "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" + "created": "\"{name}\" 위젯 생성 완료.", + "updated": "\"{name}\" 위젯 업데이트 완료.", + "deleted": "\"{name}\" 위젯 삭제 완료.", + "imported": "위젯 가져오기 완료.", + "aiPromptCopied": "AI 프롬프트 클립보드에 복사됨", + "aiPromptDescription": "사전 제작된 프롬프트를 복사하여 AI 챗봇(ChatGPT, Claude, Gemini 등)에 붙여넣습니다. 전체 위젯 스키마 및 API 응답이 포함되어 있으므로 즉시 가져올 수 있는 JSON 설정을 AI가 생성할 수 있습니다.", + "aiPromptCopy": "클립보드에 복사", + "aiPromptNoResponse": "팁: 더 나은 결과를 얻기 위해 먼저 테스트로 프롬프트에 API 응답을 포함하십시오.", + "aiPromptCopyError": "프롬프트 클립보드 복사 실패. 브라우저에서 이 기능을 지원하지 않을 수도 있습니다.", + "createError": "위젯 생성 실패. API 엔드포인트에 도달할 수 있는지 확인해 보십시오.", + "updateError": "위젯 업데이트 실패. 변경 사항이 저장되지 않습니다.", + "importError": "위젯 가져오기 실패. 파일이 올바른 사용자 지정 위젯 JSON 내보내기 형식인지 확인해 주십시오.", + "exportError": "위젯 내보내기 실패.", + "duplicated": "\"{name}\" 위젯 복사됨.", + "duplicateError": "위젯 복사 실패.", + "toggleError": "위젯 상태 전환 실패.", + "deleteError": "위젯 삭제 실패.", + "previewError": "미리보기 가져오기 실패. URL을 확인한 후 다시 시도해 주십시오.", + "executed": "작업 실행 완료.", + "executeError": "작업 실패: {error}" }, "table": { - "name": "", - "url": "", - "display": "" + "name": "이름", + "url": "URL", + "display": "표시" }, "widget": { - "disabled": "" + "disabled": "위젯 비활성화됨" } }, "integration": { @@ -995,34 +995,34 @@ "detected": "" }, "category": { - "dnsHole": "", - "mediaService": "", - "calendar": "", - "mediaSearch": "", - "mediaRelease": "", - "mediaRequest": "", + "dnsHole": "DNS", + "mediaService": "미디어", + "calendar": "달력", + "mediaSearch": "검색", + "mediaRelease": "릴리즈", + "mediaRequest": "요청", "downloadClient": "", "usenet": "", "torrent": "", "miscellaneous": "", "smartHomeServer": "", "indexerManager": "", - "healthMonitoring": "", - "search": "", - "mediaTranscoding": "", - "networkController": "", - "releasesProvider": "", - "notifications": "", - "firewall": "", - "timetable": "", - "photoService": "", - "documents": "", - "notes": "", - "mediaMonitoring": "", - "speedtest": "", - "analytics": "", - "mediaLibrary": "", - "uptimeMonitoring": "" + "healthMonitoring": "건강", + "search": "검색", + "mediaTranscoding": "트랜스코딩", + "networkController": "네트워크", + "releasesProvider": "릴리즈", + "notifications": "알림", + "firewall": "방화벽", + "timetable": "시간표", + "photoService": "사진", + "documents": "문서", + "notes": "메모", + "mediaMonitoring": "모니터링", + "speedtest": "속도 테스트", + "analytics": "분석", + "mediaLibrary": "미디어 라이브러리", + "uptimeMonitoring": "업타임 모니터링" }, "testConnection": { "action": { @@ -1333,8 +1333,8 @@ } }, "media": { - "plural": "", - "search": "", + "plural": "미디어", + "search": "미디어 찾기", "field": { "name": "이름", "size": "크기", @@ -1342,26 +1342,26 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "미디어 업로드", + "file": "파일 선택", "notification": { "success": { - "message": "" + "message": "미디어 업로드 완료" }, "error": { - "message": "" + "message": "미디어를 업로드할 수 없습니다" } } }, "delete": { - "label": "", - "description": "", + "label": "미디어 삭제", + "description": " 미디어를 삭제하시겠습니까?", "notification": { "success": { - "message": "" + "message": "미디어 삭제 완료" }, "error": { - "message": "" + "message": "미디어를 삭제할 수 없습니다" } } }, @@ -1389,65 +1389,65 @@ "create": "만들기", "createAnother": "", "edit": "수정", - "import": "", - "insert": "", + "import": "가져오기", + "insert": "삽입", "remove": "제거", "save": "저장", "saveChanges": "변경 사항 저장", "cancel": "취소", "delete": "삭제", - "discard": "", - "close": "", + "discard": "버리기", + "close": "닫기", "confirm": "확인", - "continue": "", + "continue": "계속", "previous": "이전", "next": "다음", - "checkoutDocs": "", - "checkLogs": "", + "checkoutDocs": "문서 읽기", + "checkLogs": "로그에서 상세 정보 확인", "tryAgain": "다시 시도", - "loading": "", - "show": "", - "hide": "" + "loading": "불러오는 중", + "show": "표시", + "hide": "숨기기" }, - "here": "", + "here": "여기", "iconPicker": { - "label": "", - "header": "" + "label": "아이콘 URL", + "header": "이름 또는 주제를 입력해 아이콘을 필터링하세요... Homarr가 {countIcons}에서 아이콘을 검색합니다." }, "colorScheme": { "options": { - "auto": "", - "light": "", - "dark": "" + "auto": "자동", + "light": "라이트", + "dark": "다크" } }, "information": { - "min": "", - "max": "", - "days": "", - "hours": "", - "minutes": "" + "min": "최소", + "max": "최대", + "days": "일", + "hours": "시간", + "minutes": "분" }, "notification": { "create": { - "success": "", - "error": "" + "success": "생성 완료", + "error": "생성 실패" }, "delete": { - "success": "", - "error": "" + "success": "삭제 완료", + "error": "삭제 실패" }, "update": { - "success": "", - "error": "" + "success": "변경 사항 적용 완료", + "error": "변경 사항 적용 실패" }, "transfer": { - "success": "", - "error": "" + "success": "전송 완료", + "error": "전송 실패" } }, "multiSelect": { - "placeholder": "" + "placeholder": "하나 이상의 값 선택" }, "multiText": { "placeholder": "", @@ -1456,31 +1456,31 @@ "select": { "placeholder": "", "badge": { - "recommended": "" + "recommended": "추천" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "다크 모드로 전환", + "switchToLightMode": "라이트 모드로 전환", + "management": "관리", "preferences": "기본 설정", - "logout": "", + "logout": "로그아웃", "login": "로그인", - "homeBoard": "", - "loggedOut": "", - "updateAvailable": "" + "homeBoard": "당신의 홈 보드", + "loggedOut": "로그아웃됨", + "updateAvailable": "{countUpdates} 업데이트 가능: {tag}" } }, "dangerZone": "위험한 설정", "noResults": "결과를 찾을 수 없습니다.", - "unsavedChanges": "", - "servers": "", - "applications": "", - "services": "", + "unsavedChanges": "저장하지 않은 변경 사항이 있습니다!", + "servers": "서버", + "applications": "앱", + "services": "서비스", "preview": { - "show": "", - "hide": "" + "show": "미리보기 표시", + "hide": "미리보기 숨기기" }, "zod": { "errors": { @@ -1490,7 +1490,7 @@ "startsWith": "이 필드는 {startsWith}로 시작해야 합니다.", "endsWith": "이 필드는 {endsWith}으로 끝나야 합니다.", "includes": "이 필드에는 {includes}", - "invalidEmail": "" + "invalidEmail": "이 입력란은 유효한 이메일이어야 합니다" }, "tooSmall": { "string": "이 필드는 {minimum} 자 이상이어야 합니다.", @@ -1501,8 +1501,8 @@ "number": "이 필드는 {maximum}보다 작거나 같아야 합니다." }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", + "passwordsDoNotMatch": "패스워드가 일치하지 않습니다", + "passwordRequirements": "패스워드가 요구사항을 충족하지 않습니다", "boardAlreadyExists": "", "invalidFileType": "", "invalidFileName": "", @@ -1628,85 +1628,85 @@ "propagationNotice": "" }, "advancedOptions": { - "label": "", - "title": "" + "label": "고급 옵션", + "title": "고급 항목 옵션" }, "field": { "integrations": { - "label": "" + "label": "통합" }, "title": { - "label": "" + "label": "제목" }, "customCssClasses": { - "label": "" + "label": "사용자 지정 css 클래스" }, "borderColor": { - "label": "" + "label": "테두리 색상" } } }, "remove": { - "title": "", - "message": "" + "title": "항목 제거", + "message": "이 항목을 제거하시겠습니까?" } }, "widget": { "integrationSelect": { - "configureIntegrationFirst": "", - "loading": "", - "placeholder": "", - "noResults": "", - "loadError": "" + "configureIntegrationFirst": "먼저 통합에 연결하십시오", + "loading": "불러오는 중...", + "placeholder": "옵션 선택", + "noResults": "결과 없음", + "loadError": "옵션 불러오기 실패" }, "app": { - "name": "", - "description": "", + "name": "앱", + "description": "모드에 앱을 내장합니다.", "option": { "appId": { - "label": "" + "label": "앱 선택" }, "openInNewTab": { "label": "새 탭에서 열기" }, "showTitle": { - "label": "" + "label": "앱 이름 표시" }, "pingEnabled": { - "label": "" + "label": "상태 체크 활성화" }, "layout": { - "label": "", + "label": "레이아웃", "option": { - "row": "", - "row-reverse": "", - "column": "", - "column-reverse": "" + "row": "가로", + "row-reverse": "가로(역방향)", + "column": "세로", + "column-reverse": "세로(역방향)" } }, "descriptionDisplayMode": { - "label": "", - "description": "", + "label": "설명 표시 모드", + "description": "앱 설명 표시 방법 선택", "option": { - "normal": "", - "tooltip": "", - "hidden": "" + "normal": "위젯 내부", + "tooltip": "툴팁 사용", + "hidden": "숨김" } } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "앱 없음", + "tooltip": "올바른 앱을 선택하지 않았습니다" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "북마크", + "description": "여러 앱 링크 표시", "option": { "title": { - "label": "" + "label": "제목" }, "layout": { "label": "레이아웃", @@ -1718,31 +1718,31 @@ "label": "세로" }, "grid": { - "label": "" + "label": "그리드" }, "gridHorizontal": { - "label": "" + "label": "가로 그리드" } } }, "hideTitle": { - "label": "" + "label": "제목 숨기기" }, "hideIcon": { - "label": "" + "label": "아이콘 숨기기" }, "hideHostname": { - "label": "" + "label": "호스트네임 숨기기" }, "openNewTab": { - "label": "" + "label": "새 탭에서 열기" }, "withBorder": { - "label": "" + "label": "테두리 표시" }, "items": { - "label": "", - "add": "" + "label": "북마크", + "add": "북마크 추가" } } }, @@ -3774,86 +3774,86 @@ "board": { "action": { "duplicate": { - "title": "", - "message": "", + "title": "보드 복사", + "message": "{name} 보드 및 모든 컨텐츠를 복사합니다. 사용할 수 없는 통합을 참조하는 위젯일 경우 제거됩니다.", "notification": { "success": { - "title": "", - "message": "" + "title": "보드 복사됨", + "message": "보드 복사 완료" }, "error": { - "title": "", - "message": "" + "title": "보드를 복사할 수 없습니다", + "message": "보드를 복사할 수 없었습니다" } } }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "변경 사항 적용 완료", + "message": "보드 저장이 완료되었습니다" }, "error": { - "title": "", - "message": "" + "title": "변경 사항 적용 실패", + "message": "보드를 저장할 수 없었습니다" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "저장되지 않은 변경 사항", + "message": "저장되지 않은 변경 사항이 있습니다. 나가시겠습니까?" } }, "oldImport": { - "label": "", + "label": "1.0.0 이전의 Homarr에서 가져오기", "notification": { "success": { - "title": "", - "message": "" + "title": "가져오기 완료", + "message": "보드 가져오기가 완료되었습니다" }, "error": { - "title": "", - "message": "" + "title": "가져오기 실패", + "message": "보드를 가져올 수 없었습니다, 상세 내용은 로그를 확인해 주십시오" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "JSON 파일 선택", + "invalidError": "올바르지 않은 설정 파일" }, "apps": { "label": "앱", "avoidDuplicates": { - "label": "", - "description": "" + "label": "중복 방지", + "description": "동일한 href를 가진 앱에서는 가져오기 내용을 무시합니다" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "앱만 가져오기", + "description": "앱만 추가합니다. 보드는 수동으로 다시 생성해야 합니다" } }, "name": { - "label": "" + "label": "보드 이름" }, "screenSize": { - "label": "", - "description": "", + "label": "화면 크기", + "description": "1.0 이전 버전에서는 세 가지의 다른 모드가 존재했으므로 각 화면 크기에 맞는 열 수를 선택할 수 있었습니다.", "option": { - "sm": "", - "md": "", - "lg": "" + "sm": "작음", + "md": "중간", + "lg": "큼" } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "사이드바 행동", + "description": "사이드바는 1.0에서 제거되었으며, 그 안에 있던 항목을 어떻게 처리할지 선택할 수 있습니다.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "마지막 섹션", + "description": "마지막 섹션 아래에 사이드바를 표시합니다" }, "removeItems": { - "label": "", - "description": "" + "label": "항목 제거", + "description": "사이드바 내에 있는 항목을 제거합니다" } } } @@ -3861,29 +3861,29 @@ }, "quickCreateApp": { "modal": { - "title": "", - "createAndUse": "" + "title": "즉석 앱 생성", + "createAndUse": "생성 및 사용" } } }, "field": { "pageTitle": { - "label": "" + "label": "페이지 제목" }, "metaTitle": { - "label": "" + "label": "메타 제목" }, "logoImageUrl": { - "label": "" + "label": "로고 이미지 URL" }, "faviconImageUrl": { - "label": "" + "label": "파비콘 이미지 URL" }, "backgroundImageUrl": { - "label": "", - "placeholder": "", + "label": "배경 이미지 URL", + "placeholder": "로컬 이미지 검색을 위한 타이핑 시작", "group": { - "your": "", + "your": "내 이미지", "other": "" } }, @@ -4012,20 +4012,20 @@ "title": "" }, "behavior": { - "title": "" + "title": "동작" }, "access": { - "title": "", + "title": "접근 제어", "permission": { "item": { "view": { "label": "게시판 보기" }, "modify": { - "label": "" + "label": "보드 수정" }, "full": { - "label": "" + "label": "전체 권한" } } } @@ -4034,41 +4034,41 @@ "title": "위험한 설정", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "보드 이름 변경", + "description": "이름을 변경하면 이 보드에 대한 링크가 끊어집니다.", + "button": "이름 변경", "modal": { - "title": "" + "title": "보드 이름 변경" } }, "visibility": { - "label": "", + "label": "보드 표시 변경", "description": { - "public": "", - "private": "" + "public": "현재 이 보드는 공개되어 있습니다.", + "private": "현재 이 보드는 비공개입니다." }, "button": { - "public": "", - "private": "" + "public": "비공개로 설정", + "private": "공개로 설정" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "보드 비공개", + "description": "이 보드를 비공개하시겠습니까? 보드가 공개되지 않으며 게스트 사용자용 링크가 끊어집니다." }, "private": { - "title": "", - "description": "" + "title": "보드 공개", + "description": "이 보드를 공개하시겠습니까? 모든 사람이 보드에 접근할 수 있습니다." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "이 보드 삭제", + "description": "보드를 삭제하면 되돌릴 수 없습니다. 다시 한 번 확인해 주십시오.", + "button": "이 보드 삭제", "confirm": { "title": "게시판 삭제", - "description": "" + "description": "이 보드를 삭제하시겠습니까? 보드 및 모든 컨텐츠가 영구적으로 삭제됩니다." } } } @@ -4077,33 +4077,33 @@ }, "error": { "noBoard": { - "title": "", - "description": "", - "link": "", - "notice": "" + "title": "Homarr에 오신 것을 환영합니다", + "description": "모든 앱과 서비스를 손끝에서 바로 이용할 수 있는, 세련되고 현대적인 대시보드.", + "link": "첫 번째 보드 만들기", + "notice": "이 페이지를 사라지게 하려면 보드를 만들어 홈 보드로 설정하십시오" }, "notFound": { - "title": "", - "description": "", - "link": "", - "notice": "" + "title": "보드 없음", + "description": "지정된 보드를 찾을 수 없거나 액세스할 수 없습니다.", + "link": "모든 보드 보기", + "notice": "링크를 확인하거나, 접근 가능하다고 생각되면 관리자에게 문의하십시오" }, "homeBoard": { - "title": "", + "title": "홈 보드 없음", "admin": { - "description": "", - "link": "", - "notice": "" + "description": "서버의 홈 보드를 아직 설정하지 않았습니다.", + "link": "서버 전체 홈 보드 구성", + "notice": "모든 사용자에게 이 페이지를 사라지게 하려면 서버 홈 보드를 설정하십시오" }, "user": { - "description": "", - "link": "", - "notice": "" + "description": "아직 홈 보드를 설정하지 않았습니다.", + "link": "홈 보드 구성하기", + "notice": "이 페이지를 사라지게 하려면 설정에서 홈 보드를 지정하십시오" }, "anonymous": { - "description": "", - "link": "", - "notice": "" + "description": "서버 관리자가 홈 보드를 아직 설정하지 않았습니다.", + "link": "공개 보드 보기", + "notice": "이 페이지를 사라지게 하려면 관리자에게 서버 홈 보드를 설정을 문의하십시오" } } } @@ -4111,34 +4111,34 @@ "layout": { "field": { "name": { - "label": "" + "label": "이름" }, "columnCount": { - "label": "" + "label": "열 개수" }, "breakpoint": { - "label": "", - "description": "" + "label": "중단점", + "description": "레이아웃은 이 중단점보다 크고 다음 중단점보다 작은 경우 사용됩니다." } } }, "management": { - "metaTitle": "", + "metaTitle": "관리", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "좋은 아침입니다, {username}", + "afternoon": "좋은 오후입니다, {username}", + "evening": "좋은 저녁입니다, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "찾을 수 없음", + "text": "요청한 리소스를 찾을 수 없습니다" }, "navbar": { "items": { "home": "홈", "boards": "보드", "apps": "앱", - "integrations": "", + "integrations": "통합", "customWidgets": "", "searchEngies": "", "medias": "", @@ -4287,13 +4287,13 @@ }, "name": { "management": "", - "dashboard": "" + "dashboard": "대시보드" } } } }, "security": { - "title": "" + "title": "보안" }, "board": { "title": "보드" @@ -4304,50 +4304,50 @@ "title": "사용자" }, "edit": { - "metaTitle": "" + "metaTitle": "사용자 {username} 편집" }, "create": { "metaTitle": "사용자 만들기", - "title": "", + "title": "신규 사용자 생성", "step": { "personalInformation": { - "label": "" + "label": "개인 정보" }, "security": { - "label": "" + "label": "보안" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "그룹", + "title": "기본 그룹 선택", + "description": "{everyoneGroup} 그룹은 모든 사용자에게 할당되며 제거할 수 없습니다." }, "review": { - "label": "" + "label": "리뷰" }, "completed": { - "title": "" + "title": "사용자 생성됨" }, "error": { - "title": "" + "title": "사용자 생성 실패" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "다른 사용자 생성", + "back": "사용자 목록으로 돌아가기" } }, "invite": { "title": "사용자 초대 관리", "action": { "new": { - "title": "", + "title": "새 초대", "description": "만료 후에는 초대가 더 이상 유효하지 않으며 초대를 받은 사람은 계정을 만들 수 없습니다." }, "copy": { - "title": "", - "description": "", + "title": "초대 복사", + "description": "초대장이 생성되었습니다. 이 창이 닫히면 이 링크를 더 이상 복사할 수 없습니다. 해당 사용자를 초대하고 싶지 않다면 언제든지 이 초대장을 삭제할 수 있습니다.", "link": "초대 링크", - "button": "" + "button": "복사 후 닫기" }, "delete": { "title": "초대 삭제", @@ -4356,7 +4356,7 @@ }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { "label": "크리에이터" @@ -4371,30 +4371,30 @@ } }, "group": { - "back": "", + "back": "그룹 목록으로 돌아가기", "setting": { "general": { "title": "일반", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "소유자", + "ownerOfGroup": "이 그룹의 소유자", + "ownerOfGroupDeleted": "이 그룹의 소유자가 삭제되었습니다. 현재 소유자가 없습니다." }, "setting": { - "title": "", - "alert": "", + "title": "설정", + "alert": "그룹 설정은 목록의 그룹 순서에 따라 우선순위가 매겨집니다. 상위 설정은 하위 설정을 덮어씁니다.", "board": { - "title": "" + "title": "보드" } }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "멤버", + "search": "멤버 찾기", + "notFound": "멤버 없음" }, "permissions": { - "title": "", + "title": "권한", "form": { - "unsavedChanges": "" + "unsavedChanges": "저장하지 않은 변경 사항이 있습니다!" } } } @@ -4403,61 +4403,49 @@ "title": "설정", "notification": { "success": { - "message": "" + "message": "설정 저장 완료" }, "error": { - "message": "" + "message": "설정 저장 실패" } }, "section": { "analytics": { - "title": "", + "title": "분석", "general": { - "title": "", - "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" + "title": "Homarr 개선 돕기", + "text": "사람들이 실제로 어떤 기능을 사용하는지 파악하여 개발 우선순위에 참고할 수 있습니다. 위젯 및 통합 개수, Homarr 버전, 데이터베이스 종류 등을 확인할 수 있습니다. 개인 정보, URL, 이름, 사용자 또는 설정 내용을 식별할 수 있는 사항은 수집되지 않습니다." } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "크롤링 및 인덱싱", + "warning": "이곳의 설정을 활성화/비활성화하면 검색 엔진이 페이지를 인덱싱 및 크롤링하는 방식에 큰 영향을 미칩니다. 모든 설정은 요청이며 설정을 적용하는 것은 크롤러의 권한입니다. 수정 사항은 적용되는 데에 며칠 또는 몇 주가 소요될 수 있습니다. 일부 설정은 검색 엔진에 따라 달라질 수 있습니다.", "noIndex": { - "title": "", - "text": "" + "title": "인덱싱 거부", + "text": "검색 엔진이 웹사이트를 인덱싱하고 검색 결과에 표시하지 않도록 요청합니다" }, "noFollow": { - "title": "", - "text": "" + "title": "팔로우 거부", + "text": "인덱싱하는 동안 링크를 팔로우하지 않도록 요청합니다. 비활성화하면 크롤러가 Homarr 내 모든 링크에 대한 팔로우를 시도합니다." }, "noTranslate": { - "title": "", - "text": "" + "title": "번역 없음", + "text": "사이트 언어가 사용자가 읽고 싶어하지 않을 가능성이 높을 경우 Google은 검색 결과에 번역 링크를 표시합니다" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "사이트 링크 검색창 없음", + "text": "Google은 크롤링된 링크 및 다른 직접 연결 링크로 검색 상자를 만듭니다. 이 설정을 활성화하면 Google에 해당 검색창을 비활성화하도록 요청합니다." } }, "board": { "title": "보드", "homeBoard": { - "label": "", - "mobileLabel": "", - "description": "" + "label": "글로벌 홈 보드", + "mobileLabel": "글로벌 모바일 보드", + "description": "공개 보드만 선택할 수 있습니다" }, "status": { - "title": "", + "title": "앱 상태", "enableStatusByDefault": { "label": "", "description": "" @@ -4601,77 +4589,77 @@ "weeklyMonday": "", "update": { "success": { - "message": "" + "message": "간격 업데이트 완료" }, "error": { - "message": "" + "message": "간격 업데이트 실패" } } }, "settings": { - "title": "" + "title": "{jobName} 작업 설정" }, "field": { "name": { - "label": "" + "label": "이름" }, "interval": { - "label": "" + "label": "스케줄 간격" }, "lastExecution": { - "label": "" + "label": "최근 실행" }, "actions": { - "label": "" + "label": "동작" } }, "table": { - "search": "" + "search": "{count}개 작업 검색..." }, "action": { "refresh": { - "label": "" + "label": "새로고침" } }, "refresh": { "success": { - "message": "" + "message": "작업 새로고침 완료" }, "error": { - "message": "" + "message": "작업 새로고침 실패" } }, "trigger": { "success": { - "message": "" + "message": "작업 트리거 성공" }, "error": { - "message": "" + "message": "작업 트리거 실패" } }, "enable": { "success": { - "message": "" + "message": "작업 활성화 완료" } }, "disable": { "success": { - "message": "" + "message": "작업 활성화 실패" } }, "toggle": { "error": { - "message": "" + "message": "작업 상태 전환 실패" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "API 토큰 생성됨", + "description": "API 토큰이 생성되었습니다. 이 토큰은 데이터베이스에서 암호화되어 다시는 전송되지 않습니다. 이 토큰을 분실하면 더 이상 이 토큰을 복원할 수 없습니다.", + "button": "복사 및 닫기" } }, "tab": { @@ -4679,56 +4667,56 @@ "label": "문서" }, "apiKey": { - "label": "", - "title": "", + "label": "인증", + "title": "API 키", "button": { - "createApiToken": "" + "createApiToken": "API 토큰 생성" }, "modal": { "delete": { - "title": "", - "text": "" + "title": "API 토큰 삭제", + "text": "API 토큰을 영구적으로 삭제합니다. 이 토큰을 사용하는 API 클라이언트는 더 이상 API 요청을 인증 및 수행할 수 없습니다. 이 작업은 되돌릴 수 없습니다." } }, "table": { "header": { - "id": "", - "createdBy": "", - "actions": "" + "id": "ID", + "createdBy": "생성자", + "actions": "동작" } } }, "mcp": { - "label": "", - "title": "", - "subtitle": "", - "description": "", - "noApiKey": "", - "createApiKeyButton": "", + "label": "AI / MCP", + "title": "AI 통합", + "subtitle": "모델 컨텍스트 프로토콜(MCP) 서버", + "description": "AI 어시스턴스를 Homarr 인스턴스에 연결하여 자연어로 홈랩 전체를 제어합니다. AI 어시스턴트를 통해 Overseerr 미디어 검색 및 요청, Docker 컨테이너 관리, Pi-hole 전환, 서버 상태 확인, Home Assistant 기기 제어 등의 기능을 수행할 수 있습니다.", + "noApiKey": "MCP 서버에서 인증하려면 API 키가 필요합니다.", + "createApiKeyButton": "API 키 생성", "endpoint": { - "title": "" + "title": "MCP 엔드포인트" }, "authentication": { - "title": "", - "intro": "", + "title": "인증", + "intro": "MCP 서버는 API 키 또는 OAuth를 사용해 인증할 수 있습니다. 두 방법 모두 동일한 수준의 접근 권한을 부여합니다.", "apiKey": { - "title": "", - "description": "" + "title": "API 키(수동)", + "description": "MCP 클라이언트 설정에서 전체 API 키와 함께 APIKey 헤더를 전달합니다." }, "oauth": { - "title": "", - "description": "", - "hint": "" + "title": "OAuth(브라우저 로그인)", + "description": "OAuth를 지원하는 클라이언트(Claude Code, opencode, Cursor 등)는 브라우저 창을 열어 인증할 수 있습니다. 클라이언트에서 인증 명령을 실행하고 브라우저에서 Homarr에 로그인하면 연결됩니다. API 키가 자동으로 생성됩니다.", + "hint": "OAuth 토큰은 인증 탭에 일반 API 키로 표시됩니다. 언제든지 철회할 수 있습니다." }, - "permissions": "" + "permissions": "API 키는 AI가 사용할 수 있는 권한을 결정하며, 키 소유자와 동일한 접근 수준에서 작동합니다." }, "clientConfig": { - "title": "", + "title": "클라이언트 설정", "streamableHttp": { - "recommended": "", - "title": "", - "worksWith": "", - "addToConfig": "", + "recommended": "권장", + "title": "스트리밍 가능한 HTTP", + "worksWith": "작동: Cursor, Claude Desktop, VS Code Copilot, Windsurf, Claude Code", + "addToConfig": "MCP 클라이언트 설정 파일에 추가:", "cursor": "", "claudeDesktop": "", "claudeCode": "", @@ -4811,70 +4799,70 @@ "description": "", "warning": "", "dropzone": { - "title": "", - "description": "" + "title": "백업 ZIP을 여기에 놓거나 클릭하여 탐색", + "description": "Homarr SQLite 백업에서는 .zip 파일만 허용됩니다" }, - "changeFile": "", - "button": "", + "changeFile": "파일 변경", + "button": "데이터베이스 복원", "success": { - "title": "", - "message": "" + "title": "복원 완료", + "message": "데이터베이스 복원 완료. 앱이 재시작됩니다..." }, - "error": "" + "error": "가져오기 실패" }, "preview": { - "title": "", - "exported": "", - "loading": "", - "errorTitle": "", - "entity": "", - "count": "", - "boards": "", + "title": "컨텐츠 백업", + "exported": "{date}에 내보냄", + "loading": "백업 파일 분석 중...", + "errorTitle": "미리보기 오류", + "entity": "엔티티", + "count": "수량", + "boards": "보드", "entities": { - "board": "", - "user": "", - "app": "", - "integration": "", - "item": "", - "media": "", - "search_engine": "" + "board": "보드", + "user": "사용자", + "app": "앱", + "integration": "통합", + "item": "위젯", + "media": "미디어", + "search_engine": "검색 엔진" }, - "analyzeError": "", - "invalidMissingMetadata": "", - "invalidMissingDb": "" + "analyzeError": "백업 파일 분석 실패", + "invalidMissingMetadata": "올바르지 않은 백업: metadata.json 없음", + "invalidMissingDb": "올바르지 않은 백업: db.sqlite 없음" }, "restore": { "dropzone": { - "title": "", - "description": "" + "title": "여기에 백업 ZIP 놓기", + "description": "Homarr SQLite 백업에서는 .zip 파일을 허용합니다(최대 256MB)" }, - "analyzing": "", - "changeFile": "", - "continueToRestore": "", - "tryAgain": "", - "analysisError": "", + "analyzing": "백업 분석 중...", + "changeFile": "파일 변경", + "continueToRestore": "복원하려면 계속", + "tryAgain": "다시 시도", + "analysisError": "분석 오류", "preview": { - "title": "", - "exported": "", - "entity": "", - "count": "", - "boards": "", + "title": "컨텐츠 백업", + "exported": "{date}에 내보냄", + "entity": "엔티티", + "count": "수량", + "boards": "보드", "entities": { - "board": "", - "user": "", - "app": "", - "integration": "", - "item": "", - "media": "", - "search_engine": "" + "board": "보드", + "user": "사용자", + "app": "앱", + "integration": "통합", + "item": "위젯", + "media": "미디어", + "search_engine": "검색 엔진" }, - "migrationsApplied": "", - "migrationsAppliedPlural": "", - "migrationsOlderVersion": "", - "migrationsOlderVersionPlural": "", - "migrationsUpToDate": "", - "upToDate": "", - "migrationsPending": "" + "migrationsApplied": "{count}개 마이그레이션 적용", + "migrationsAppliedPlural": "{count}개 마이그레이션 적용", + "migrationsOlderVersion": "이 백업은 이전 Homarr 버전에서 가져온 것입니다. {count}개의 스키마 마이그레이션이 최신 상태로 적용되었습니다.", + "migrationsOlderVersionPlural": "이 백업은 이전 Homarr 버전에서 가져온 것입니다. {count}개의 스키마 마이그레이션이 최신 상태로 적용되었습니다.", + "migrationsUpToDate": "데이터베이스 스키마가 최신 상태입니다({count}개 마이그레이션 적용)", + "upToDate": "최신", + "migrationsPending": "{count}개 대기 중" }, "migration": { "title": "", @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { @@ -5325,32 +5315,32 @@ } }, "permission": { - "title": "", + "title": "권한", "userSelect": { - "title": "" + "title": "사용자 권한 추가" }, "groupSelect": { - "title": "" + "title": "그룹 권한 추가" }, "tab": { "user": "사용자", - "group": "", - "inherited": "" + "group": "그룹", + "inherited": "하위 그룹" }, "field": { "user": { "label": "사용자" }, "group": { - "label": "" + "label": "그룹" }, "permission": { - "label": "" + "label": "권한" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "사용자 권한 저장", + "saveGroup": "그룹 권한 저장" } }, "navigationStructure": { @@ -5360,44 +5350,44 @@ "label": "보드" }, "integrations": { - "label": "", + "label": "통합", "edit": { "label": "수정" }, "new": { - "label": "" + "label": "신규" } }, "search-engines": { - "label": "", + "label": "검색 엔진", "new": { - "label": "" + "label": "신규" }, "edit": { "label": "수정" } }, "medias": { - "label": "" + "label": "미디어" }, "apps": { "label": "앱", "new": { - "label": "" + "label": "신규" }, "edit": { "label": "수정" } }, "custom-widgets": { - "label": "", + "label": "사용자 지정 위젯", "new": { - "label": "" + "label": "신규" }, "edit": { - "label": "", + "label": "편집", "flow": { - "label": "" + "label": "플로우" } } }, @@ -5407,10 +5397,10 @@ "label": "만들기" }, "general": "일반", - "security": "", + "security": "보안", "board": "보드", "groups": { - "label": "" + "label": "그룹" }, "invites": { "label": "초대" @@ -5419,16 +5409,16 @@ "tools": { "label": "도구", "tasks": { - "label": "" + "label": "작업" }, "docker": { - "label": "", + "label": "Docker", "logs": { - "label": "" + "label": "로그" } }, "kubernetes": { - "label": "", + "label": "Kubernetes", "nodes": { "label": "" }, @@ -5455,12 +5445,12 @@ } }, "logs": { - "label": "" + "label": "로그" }, "certificates": { - "label": "", + "label": "인증서", "hostnames": { - "label": "" + "label": "호스트네임" } } }, @@ -5473,28 +5463,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "무엇이든 검색", + "nothingFound": "결과 없음", "error": { - "fetch": "" + "fetch": "데이터를 가져오는 중 오류가 발생했습니다" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "앱, 통합, 보드 검색", "group": { "app": { "title": "앱", "children": { "action": { "open": { - "label": "" + "label": "앱 URL 열기" }, "edit": { - "label": "" + "label": "앱 편집" } }, "detail": { - "title": "" + "title": "앱 동작 선택" } } }, @@ -5503,55 +5493,55 @@ "children": { "action": { "open": { - "label": "" + "label": "보드 열기" }, "homeBoard": { - "label": "" + "label": "홈 보드로 설정" }, "mobileBoard": { - "label": "" + "label": "모바일 보드로 설정" }, "settings": { - "label": "" + "label": "설정 열기" } }, "detail": { - "title": "" + "title": "보드 동작 선택" } } }, "integration": { - "title": "" + "title": "통합" } } }, "command": { - "help": "", + "help": "커맨드 모드 활성화", "group": { "localCommand": { - "title": "" + "title": "로컬 커맨드" }, "globalCommand": { - "title": "", + "title": "글로벌 커맨드", "option": { "colorScheme": { - "auto": "", - "light": "", - "dark": "" + "auto": "외형 모드 전환", + "light": "라이트 모드로 전환", + "dark": "다크 모드로 전환" }, "language": { - "label": "", + "label": "언어 변경", "children": { "detail": { - "title": "" + "title": "선호하는 언어를 선택하십시오" } } }, "newBoard": { - "label": "" + "label": "새 보드 생성" }, "importBoard": { - "label": "" + "label": "보드 가져오기" }, "newApp": { "label": "" @@ -5638,34 +5628,34 @@ } }, "ddgBangs": { - "label": "", + "label": "DuckDuckGo bangs 활성화", "children": { "detail": { - "title": "" + "title": "DuckDuckGo bangs 활성화" } } }, "firstDayOfWeek": { - "label": "", + "label": "주 시작 요일", "children": { "detail": { - "title": "" + "title": "한 주의 시작 요일을 선택하십시오" } } }, "homeBoardId": { - "label": "", + "label": "홈 보드", "children": { "detail": { - "title": "" + "title": "홈 보드를 선택하십시오" } } }, "mobileHomeBoardId": { - "label": "", + "label": "모바일 홈 보드", "children": { "detail": { - "title": "" + "title": "모바일 홈 보드를 선택하십시오" } } }, @@ -5678,7 +5668,7 @@ } }, "fullPreferencesPage": { - "label": "" + "label": "전체 설정 페이지 열기" } } } @@ -5714,11 +5704,11 @@ "help": "", "group": { "searchEngine": { - "title": "", + "title": "검색 엔진", "tipDdgBangs": "", "bang": { "searchWithQuery": "", - "pressEnterToOpen": "", + "pressEnterToOpen": "Enter 키로 열기", "engineSelected": "", "typeQueryToContinue": "", "emptyBangHint": "" @@ -5730,7 +5720,7 @@ } }, "detail": { - "title": "" + "title": "검색 엔진 동작 선택" }, "searchResults": { "title": "" @@ -5738,24 +5728,24 @@ }, "option": { "google": { - "name": "", - "description": "" + "name": "Google", + "description": "Google 웹 검색" }, "bing": { - "name": "", - "description": "" + "name": "Bing", + "description": "Bing 웹 검색" }, "duckduckgo": { - "name": "", - "description": "" + "name": "DuckDuckGo", + "description": "DuckDuckGo 웹 검색" }, "torrent": { "name": "토렌트", - "description": "" + "description": "torrentdownloads.pro에서 토렌트 검색" }, "youTube": { - "name": "", - "description": "" + "name": "YouTube", + "description": "YouTube에서 비디오 검색" } } } @@ -5764,7 +5754,7 @@ "help": { "group": { "mode": { - "title": "" + "title": "모드" }, "help": { "title": "도움말", @@ -5773,7 +5763,7 @@ "label": "문서" }, "submitIssue": { - "label": "" + "label": "문제 보고" }, "discord": { "label": "커뮤니티 불화" @@ -5785,13 +5775,13 @@ "home": { "group": { "search": { - "title": "", + "title": "검색", "option": { "other": { - "label": "" + "label": "다른 검색 엔진으로 검색" }, "no-default": { - "label": "", + "label": "기본 검색 엔진 없음", "description": "" }, "search": { @@ -5895,11 +5885,11 @@ "label": "" }, "managePermission": { - "label": "" + "label": "권한 관리" } }, "detail": { - "title": "" + "title": "그룹 동작 선택" } } } @@ -5907,7 +5897,7 @@ } }, "engine": { - "search": "", + "search": "검색 엔진 찾기", "field": { "name": { "label": "이름" @@ -5916,63 +5906,63 @@ "label": "" }, "urlTemplate": { - "label": "" + "label": "URL 검색 템플릿" }, "description": { - "label": "" + "label": "설명" } }, "page": { "list": { - "title": "", + "title": "검색 엔진", "noResults": { - "title": "", - "action": "" + "title": "아직 검색 엔진이 없습니다", + "action": "첫 검색 엔진을 생성" }, "interactive": "" }, "create": { - "title": "", + "title": "새 검색 엔진", "notification": { "success": { - "title": "", - "message": "" + "title": "검색 엔진 생성됨", + "message": "검색 엔진 생성 완료" }, "error": { - "title": "", - "message": "" + "title": "검색 엔진 생성되지 않음", + "message": "검색 엔진 생성에 실패했습니다" } } }, "edit": { - "title": "", + "title": "검색 엔진 편집", "notification": { "success": { - "title": "", - "message": "" + "title": "변경 사항 적용 완료", + "message": "검색 엔진 저장 완료" }, "error": { - "title": "", - "message": "" + "title": "변경 사항 적용 실패", + "message": "검색 엔진 저장에 실패했습니다" } }, - "configControl": "", + "configControl": "설정", "searchEngineType": { "generic": "", "fromIntegration": "" } }, "delete": { - "title": "", - "message": "", + "title": "검색 엔진 삭제", + "message": "{name} 검색 엔진을 삭제하시겠습니까?", "notification": { "success": { - "title": "", - "message": "" + "title": "검색 엔지 삭제됨", + "message": "검색 엔진 삭제 완료" }, "error": { - "title": "", - "message": "" + "title": "검색 엔진 삭제되지 않음", + "message": "검색 엔진 삭제에 실패했습니다" } } } @@ -6002,43 +5992,43 @@ "certificate": { "field": { "hostname": { - "label": "" + "label": "호스트네임" }, "subject": { - "label": "" + "label": "주체" }, "issuer": { - "label": "" + "label": "발급자" }, "validFrom": { - "label": "" + "label": "시작일" }, "validTo": { - "label": "" + "label": "만료일" }, "serialNumber": { - "label": "" + "label": "일련번호" }, "fingerprint": { - "label": "" + "label": "핑거프린트" } }, "page": { "list": { - "title": "", - "description": "", + "title": "신뢰할 수 있는 인증서", + "description": "Homarr가 통합에서 데이터를 요청하는 데에 사용됩니다.", "noResults": { - "title": "" + "title": "아직 인증서가 없습니다" }, "invalid": { - "title": "", - "description": "" + "title": "유효하지 않은 인증서", + "description": "인증서 파싱 실패" }, - "expires": "", - "toHostnames": "" + "expires": "{when}에 만료", + "toHostnames": "신뢰할 수 있는 호스트네임" }, "hostnames": { - "title": "", + "title": "신뢰할 수 있는 인증서 호스트네임", "description": "", "noResults": { "title": "" @@ -6129,41 +6119,41 @@ }, "integrationsList": { "title": "", - "description": "" + "description": "Homarr에 연결된 서비스는 Sonarr, Radarr, Plex, Jellyfin 등 50개 이상입니다. 모든 자격증명은 정지 상태에서 암호화됩니다." }, "integrationsCreate": { - "title": "", - "description": "" + "title": "통합 추가", + "description": "여기에서 새 서비스를 연결합니다. 유형을 선택하고, URL및 API 키를 입력합니다. Homarr가 저장하기 전에 연결을 검증합니다." }, "usersList": { - "title": "", - "description": "" + "title": "사용자", + "description": "접근 권한이 있는 사용자를 확인합니다. 사용자를 그룹으로 구성하여 각 보드를 보거나 편집할 수 있는 사용자를 제어할 수 있습니다." }, "usersCreate": { - "title": "", - "description": "" + "title": "사용자 생성", + "description": "여기에서 새 사용자를 생성합니다. 초대 링크를 사용해 쉽게 온보딩할 수도 있습니다. 이것이 바로 그 투어이며 모든 것이 준비되었습니다!" } }, "board": { "welcome": { - "title": "", - "description": "" + "title": "이것이 당신의 보드입니다", + "description": "앱과 위젯을 배열할 수 있는 드래그 앤 드롭 대시보드입니다. 언제든지 Ctrl+K 키로 앱, 보드 및 작업을 검색할 수 있습니다." }, "editMode": { - "title": "", - "description": "" + "title": "편집 모드", + "description": "편집 모드로 들어가려면 여기를 클릭하십시오. 그 후 위젯, 앱, 섹션을 추가할 수 있습니다. 드래그하여 재배치하고 모서리 손잡이로 크기를 조절할 수 있습니다. 변경 사항을 저장하려면 다시 클릭하십시오." }, "settings": { - "title": "", - "description": "" + "title": "보드 설정", + "description": "이 보드의 이름, 열, 배경, 색상, 접근할 수 있는 사용자를 변경합니다. 각 보드는 공개 또는 비공개로 설정할 수 있습니다." }, "switcher": { - "title": "", - "description": "" + "title": "보드 전환", + "description": "보드를 이동합니다. 미디어, 네트워킹, 사용자별 또는 원하는 용도로 별도의 대시보드를 생성할 수 있습니다." }, "userMenu": { - "title": "", - "description": "" + "title": "당신의 프로필", + "description": "색상 구성표, 언어, 홈 보드, 설정을 변경할 수 있습니다. 여기에서 관리 영역으로 이동할 수도 있습니다." } } } diff --git a/packages/translation/src/lang/lt.json b/packages/translation/src/lang/lt.json index 052e40a2b..afec241f1 100644 --- a/packages/translation/src/lang/lt.json +++ b/packages/translation/src/lang/lt.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/lv.json b/packages/translation/src/lang/lv.json index b90556927..e5d262048 100644 --- a/packages/translation/src/lang/lv.json +++ b/packages/translation/src/lang/lv.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/nl.json b/packages/translation/src/lang/nl.json index 96c02cabf..66a8f48d1 100644 --- a/packages/translation/src/lang/nl.json +++ b/packages/translation/src/lang/nl.json @@ -4415,18 +4415,6 @@ "general": { "title": "Anonieme analyses sturen", "text": "Homarr verstuurt geanonimiseerde analyses met behulp van de open source software Umami. Het verzamelt nooit persoonlijke informatie en is daarom volledig GDPR & CCPA compliant. We moedigen je aan om analytics in te schakelen omdat het ons open source team helpt bij het identificeren van problemen en het prioriteren van onze backlog." - }, - "widgetData": { - "title": "Widgetgegevens", - "text": "Stuur welke widgets (en hun aantal) je hebt geconfigureerd. Bevat geen URL's, namen of andere gegevens." - }, - "integrationData": { - "title": "Integratiegegevens", - "text": "Stuur welke integraties (en het aantal) je hebt geconfigureerd. Bevat geen URL's, namen of andere gegevens." - }, - "usersData": { - "title": "Gebruikersgegevens", - "text": "Stuur het aantal gebruikers en of je SSO hebt geactiveerd" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "{when} bijgewerkt", "search": "{count} containers zoeken", "selected": "{selectCount} van {totalCount} containers geselecteerd", - "footer": "Totaal {count} containers" + "footer": "Totaal {count} containers", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/no.json b/packages/translation/src/lang/no.json index efd8a9c3f..00309d122 100644 --- a/packages/translation/src/lang/no.json +++ b/packages/translation/src/lang/no.json @@ -4415,18 +4415,6 @@ "general": { "title": "Send anonym brukerdata", "text": "Homarr vil sende anonymiserte analyser ved bruk av den åpne programvaren Umami. Når dette er aktivert, samler vi inn: Homarr-versjon, databastype (MySQL/PostgreSQL/SQLite), Docker/Kubernetes-status, aktiverte autentiseringsmetoder, og antallet av hver funksjon. Alle data er anonyme og aggregerte – ingen personlig informasjon, URL-er, navn eller identifiserbare data samles inn. Dette hjelper vårt open source-team med å forstå bruks‑mønstre og prioritere utvikling." - }, - "widgetData": { - "title": "Widget data", - "text": "Send hvilke widgeter (og deres antall) du har konfigurert. Inkluderer ikke nettadresser, navn eller andre data." - }, - "integrationData": { - "title": "Integrasjonsdata", - "text": "Send hvilke integrasjoner (og deres antall) du har konfigurert. Inkluderer ikke nettadresser, navn eller andre data." - }, - "usersData": { - "title": "Brukeres data", - "text": "Send antall brukere og om du har aktivert SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Oppdatert {when}", "search": "Søk {count} containere", "selected": "{selectCount} av {totalCount} containere valgt", - "footer": "Totalt {count} containere" + "footer": "Totalt {count} containere", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/pl.json b/packages/translation/src/lang/pl.json index 770558342..90aa8c3eb 100644 --- a/packages/translation/src/lang/pl.json +++ b/packages/translation/src/lang/pl.json @@ -4415,18 +4415,6 @@ "general": { "title": "Wysyłaj anonimowe dane analityczne", "text": "Homarr będzie wysyłał anonimowe dane analityczne przy użyciu oprogramowania open source Umami. Nigdy nie zbiera żadnych danych osobowych, dlatego jest w pełni zgodny z RODO i CCPA. Zachęcamy do włączenia analityki, ponieważ pomaga to naszemu zespołowi open source w identyfikowaniu problemów i ustalaniu priorytetów w backlogu." - }, - "widgetData": { - "title": "Dane widżetu", - "text": "Wyślij informacje o tym, które widżety (i w jakiej ilości) masz skonfigurowane. Nie obejmuje to adresów URL, nazw ani żadnych innych danych." - }, - "integrationData": { - "title": "Informacje o integracjach", - "text": "Wyślij informacje o tym, które integracje (i w jakiej ilości) masz skonfigurowane. Nie obejmuje to adresów URL, nazw ani żadnych innych danych." - }, - "usersData": { - "title": "Dane użytkowników", - "text": "Wyślij liczbę użytkowników oraz informację, czy SSO jest aktywne." } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Zaktualizowano {when}", "search": "Szukaj wśród {count} kontenerów", "selected": "Wybrano {selectCount} z {totalCount} kontenerów", - "footer": "Łącznie {count} kontenerów" + "footer": "Łącznie {count} kontenerów", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/pt-br.json b/packages/translation/src/lang/pt-br.json index 85fff9714..2c096f760 100644 --- a/packages/translation/src/lang/pt-br.json +++ b/packages/translation/src/lang/pt-br.json @@ -4415,18 +4415,6 @@ "general": { "title": "Enviar análises anônimas", "text": "O Homarr enviará análises anonimizadas usando o software de código aberto Umami. Quando habilitado, coletamos: versão do Homarr, tipo de banco de dados (MySQL/PostgreSQL/SQLite), status Docker/Kubernetes, métodos de autenticação habilitados e a quantidade de cada recurso. Todos os dados são anônimos e agregados - nenhuma informação pessoal, URLs, nomes ou dados identificáveis são coletados. Isso ajuda nossa equipe de código aberto a entender padrões de uso e priorizar o desenvolvimento." - }, - "widgetData": { - "title": "Dados de widgets", - "text": "Envia quais widgets (e suas quantidades) você configurou. Não inclui URLs, nomes ou quaisquer outros dados." - }, - "integrationData": { - "title": "Dados de integrações", - "text": "Envia quais integrações (e suas quantidades) você configurou. Não inclui URLs, nomes ou quaisquer outros dados." - }, - "usersData": { - "title": "Dados dos usuários", - "text": "Envia a quantidade de usuários e se você ativou SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Atualizado em {when}", "search": "Buscar {count} contêineres", "selected": "{selectCount} de {totalCount} contêineres selecionados", - "footer": "Total de contêineres: {count}" + "footer": "Total de contêineres: {count}", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/pt.json b/packages/translation/src/lang/pt.json index 77da1b636..48bf163a9 100644 --- a/packages/translation/src/lang/pt.json +++ b/packages/translation/src/lang/pt.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/ro.json b/packages/translation/src/lang/ro.json index 9de9ab222..32081e109 100644 --- a/packages/translation/src/lang/ro.json +++ b/packages/translation/src/lang/ro.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/ru.json b/packages/translation/src/lang/ru.json index 93319f30f..edca67abd 100644 --- a/packages/translation/src/lang/ru.json +++ b/packages/translation/src/lang/ru.json @@ -4415,18 +4415,6 @@ "general": { "title": "Отправлять анонимную аналитику", "text": "Homarr отправляет обезличенную аналитику с помощью открытого ПО Umami. При включении собираются: версия Homarr, тип базы данных (MySQL/PostgreSQL/SQLite), статус Docker/Kubernetes, включённые методы аутентификации и количество используемых функций. Все данные анонимны и агрегированы - личная информация, URL-адреса, имена и другие идентифицирующие данные никогда не собираются. Это помогает нашей команде понимать типичные сценарии использования и определять приоритеты в разработке." - }, - "widgetData": { - "title": "Данные о виджетах", - "text": "Отправлять информацию о настроенных виджетах (и их количестве). Не включает URL-адреса, названия или другие данные." - }, - "integrationData": { - "title": "Данные об интеграциях", - "text": "Отправлять информацию о настроенных интеграциях (и их количестве). Не включает URL-адреса, названия или другие данные." - }, - "usersData": { - "title": "Данные о пользователях", - "text": "Отправлять количество пользователей и информацию об использовании единого входа" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Обновлено {when}", "search": "Поиск среди {count} контейнеров", "selected": "Выбрано {selectCount} из {totalCount} контейнеров", - "footer": "Всего {count} контейнеров" + "footer": "Всего {count} контейнеров", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/sk.json b/packages/translation/src/lang/sk.json index 94c02b629..3e44a4be6 100644 --- a/packages/translation/src/lang/sk.json +++ b/packages/translation/src/lang/sk.json @@ -4415,18 +4415,6 @@ "general": { "title": "Odoslať anonymné analýzy", "text": "Homarr bude posielať anonymizované analýzy pomocou open source softvéru Umami. Nikdy nezhromažďuje žiadne osobné údaje, a preto je plne v súlade s GDPR a CCPA. Odporúčame vám povoliť analýzu, pretože pomáha nášmu tímu s otvoreným zdrojom identifikovať problémy a uprednostňovať naše nevybavené veci." - }, - "widgetData": { - "title": "Údaje widgetu", - "text": "Pošlite, ktoré widgety (a ich množstvo) ste nakonfigurovali. Nezahŕňa adresy URL, mená ani iné údaje." - }, - "integrationData": { - "title": "Integračné údaje", - "text": "Pošlite, ktoré integrácie (a ich množstvo) ste nakonfigurovali. Nezahŕňa adresy URL, mená ani iné údaje." - }, - "usersData": { - "title": "Údaje o používateľoch", - "text": "Pošlite počet používateľov a či ste aktivovali jednotné prihlásenie" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Aktualizované {when}", "search": "Vyhľadajte {count} kontajnery", "selected": "{selectCount} z {totalCount} vybratých kontajnerov", - "footer": "Celkový počet kontajnerov: {count}" + "footer": "Celkový počet kontajnerov: {count}", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/sl.json b/packages/translation/src/lang/sl.json index 23dc7ea83..eec31b510 100644 --- a/packages/translation/src/lang/sl.json +++ b/packages/translation/src/lang/sl.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/sv.json b/packages/translation/src/lang/sv.json index 0924c33d8..1747bc399 100644 --- a/packages/translation/src/lang/sv.json +++ b/packages/translation/src/lang/sv.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Uppdaterad {when}", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/tr.json b/packages/translation/src/lang/tr.json index 37f42b3d1..a3acc6650 100644 --- a/packages/translation/src/lang/tr.json +++ b/packages/translation/src/lang/tr.json @@ -4415,18 +4415,6 @@ "general": { "title": "Anonim analizler gönder", "text": "Homarr, açık kaynaklı yazılım Umami'yi kullanarak anonimleştirilmiş analizler gönderecektir. Hiçbir zaman kişisel bilgi toplamaz ve bu nedenle tamamen GDPR ve CCPA uyumludur. Analizleri etkinleştirmenizi öneririz çünkü, açık kaynak yazılım ekibimizin sorunları daha hızlı belirlemesine ve birikmiş işlerimizi önceliklendirmesine yardımcı olmaktadır." - }, - "widgetData": { - "title": "Araç verileri", - "text": "Hangi araçları (ve miktarlarını) yapılandırdığınızı gönderin. URL'leri, adları veya başka herhangi bir veri içermez." - }, - "integrationData": { - "title": "Entegrasyon verileri", - "text": "Entegrasyon (ve sayıları) yapılandırma verilerini gönder. URL'leri, alan adlarını veya başka herhangi bir veriyi içermez." - }, - "usersData": { - "title": "Kullanıcı verileri", - "text": "Kullanıcı sayısını ve SSO etkinleştirme verilerini gönder" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "{when} Güncellendi", "search": "{count} konteyner içinde ara", "selected": "{selectCount} / {totalCount} konteyner seçildi", - "footer": "Toplam {count} konteyner" + "footer": "Toplam {count} konteyner", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/uk.json b/packages/translation/src/lang/uk.json index 8d81146c8..a6305e4e1 100644 --- a/packages/translation/src/lang/uk.json +++ b/packages/translation/src/lang/uk.json @@ -687,7 +687,7 @@ "customWidget": { "page": { "list": { - "title": "", + "title": "Власні віджети", "noResults": "", "loading": "" }, @@ -874,7 +874,7 @@ "exportError": "", "duplicated": "", "duplicateError": "", - "toggleError": "", + "toggleError": "Не вдалося змінити стан віджету.", "deleteError": "", "previewError": "", "executed": "", @@ -1021,7 +1021,7 @@ "mediaMonitoring": "", "speedtest": "", "analytics": "", - "mediaLibrary": "", + "mediaLibrary": "Медіа бібліотека", "uptimeMonitoring": "" }, "testConnection": { @@ -1139,7 +1139,7 @@ "description": { "connection": { "hostUnreachable": "", - "networkUnreachable": "", + "networkUnreachable": "Мережа недоступна. Перевірте підключення до Інтернету або налаштування мережі.", "refused": "", "reset": "" }, @@ -1328,7 +1328,7 @@ } }, "paperlessNgx": { - "name": "", + "name": "Безпаперовий ngx", "description": "" } }, @@ -1679,9 +1679,9 @@ "label": "", "option": { "row": "", - "row-reverse": "", + "row-reverse": "Горизонтально (зворотнє)", "column": "", - "column-reverse": "" + "column-reverse": "Вертикальна (перевернута)" } }, "descriptionDisplayMode": { @@ -1690,7 +1690,7 @@ "option": { "normal": "", "tooltip": "", - "hidden": "" + "hidden": "Приховати" } } }, @@ -1703,7 +1703,7 @@ }, "bookmarks": { "name": "Закладки", - "description": "", + "description": "Показує декілька посилань додатка", "option": { "title": { "label": "Назва" @@ -1747,8 +1747,8 @@ } }, "archiveTeamWarrior": { - "name": "", - "description": "", + "name": "АрхівTeam Warrior", + "description": "Слідкуйте за станом, проєктами та активними архівними завданнями ArchiveTeam Warrior.", "option": { "showBroadcastMessage": { "label": "" @@ -1778,7 +1778,7 @@ } }, "error": { - "internalServerError": "", + "internalServerError": "Не вдалося отримати резюме DNS Hole", "integrationsDisconnected": "Немає даних, всі інтеграції відключені" }, "data": { @@ -1808,7 +1808,7 @@ } }, "showToggleAllButtons": { - "label": "" + "label": "Показати всі кнопки" } }, "error": { @@ -4415,18 +4415,6 @@ "general": { "title": "Надсилати анонімну аналітику", "text": "Homarr буде відправляти анонімну аналітику з використанням програмного забезпечення з відкритим вихідним кодом Umami. Він ніколи не збирає жодної особистої інформації і, таким чином, сумісний з GDPR та CCPA. Ми заохочуємо вас увімкнути аналітику, тому що це допомагає нашій команді визначати проблеми та пріоритетні задачі." - }, - "widgetData": { - "title": "Дані віджетів", - "text": "Надсилати, які віджети (і їх кількість) ви налаштували. Не містить URL, назви, або будь-які інші дані." - }, - "integrationData": { - "title": "Дані інтеграції", - "text": "Надсилати, які віджети (і їх кількість) ви налаштували. Не містить URL, назви, або будь-які інші дані." - }, - "usersData": { - "title": "Дані користувачів", - "text": "Надсилати кількість користувачів і чи активували ви SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "Оновлено {when}", "search": "", "selected": "Вибрано {selectCount} із {totalCount} контейнерів", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/vi.json b/packages/translation/src/lang/vi.json index 9fbbef154..dd8e8b519 100644 --- a/packages/translation/src/lang/vi.json +++ b/packages/translation/src/lang/vi.json @@ -4415,18 +4415,6 @@ "general": { "title": "", "text": "" - }, - "widgetData": { - "title": "", - "text": "" - }, - "integrationData": { - "title": "", - "text": "" - }, - "usersData": { - "title": "", - "text": "" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "", "search": "", "selected": "", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/translation/src/lang/zh.json b/packages/translation/src/lang/zh.json index 4ba9707c4..99def3d69 100644 --- a/packages/translation/src/lang/zh.json +++ b/packages/translation/src/lang/zh.json @@ -4415,18 +4415,6 @@ "general": { "title": "發送匿名分析", "text": "Homarr 使用開源軟體 Umami 發送匿名分析,他從不收集任何個人資料,因此完全符合 GDPR 和 CCPA 要求,我們鼓勵啟用分析,因為可以幫助我們的團隊識別問題,並確認待辦事項的優先級別" - }, - "widgetData": { - "title": "小工具數據", - "text": "發送已設定的小工具 (及其數量),不包括網址、名稱或任何其他數據" - }, - "integrationData": { - "title": "集成數據", - "text": "發送已設定的集成 (及其數量),不包括網址、名稱或任何其他數據" - }, - "usersData": { - "title": "使用者資料", - "text": "發送使用者數量以及是否激活了 SSO" } }, "crawlingAndIndexing": { @@ -4954,7 +4942,9 @@ "updated": "已更新於 {when}", "search": "搜尋 {count} 容器", "selected": "{totalCount} 容器的 {selectCount}", - "footer": "" + "footer": "", + "totalCpu": "", + "totalMemory": "" }, "field": { "name": { diff --git a/packages/widgets/src/beszel-alerts/component.tsx b/packages/widgets/src/beszel-alerts/component.tsx index 82725db51..7c2bcc06c 100644 --- a/packages/widgets/src/beszel-alerts/component.tsx +++ b/packages/widgets/src/beszel-alerts/component.tsx @@ -1,7 +1,7 @@ "use client"; import { useMemo } from "react"; -import { Badge, Box, Divider, Group, ScrollArea, Stack, Text, ThemeIcon } from "@mantine/core"; +import { Badge, Box, Center, Divider, Group, Loader, ScrollArea, Stack, Text, ThemeIcon } from "@mantine/core"; import { IconBellOff, IconCircleCheck, IconFlame, IconHistory } from "@tabler/icons-react"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; @@ -12,6 +12,7 @@ import { clientApi } from "@homarr/api/client"; import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; +import { BeszelIntegrationErrorIndicator } from "../beszel/_shared/error-indicator"; const alertIconMap: Record = { CPU: Cpu, @@ -40,9 +41,14 @@ export default function BeszelAlertsWidget({ () => ({ integrationIds, includeHistory: options.showHistory, maxHistoryItems: options.maxHistoryItems }), [integrationIds, options.showHistory, options.maxHistoryItems], ); - const { data: results = [] } = clientApi.widget.beszel.getAlerts.useQuery(alertsInput, { - staleTime: 15_000, - refetchInterval: 15_000, + const { + data: results = [], + error: alertsError, + isPending, + } = clientApi.widget.beszel.getAlerts.useQuery(alertsInput, { + staleTime: 10_000, + gcTime: 48 * 60 * 60 * 1000, + refetchInterval: 10_000, retry: false, }); const utils = clientApi.useUtils(); @@ -91,113 +97,128 @@ export default function BeszelAlertsWidget({ const triggeredAlerts = alerts.filter((a) => a.triggered); const okAlerts = alerts.filter((a) => !a.triggered); + if (alertsError) throw alertsError; + + if (isPending) { + return ( +
+ +
+ ); + } + return ( - - - {alerts.length === 0 && ( - - - - - - {t("empty")} - - - )} - - {triggeredAlerts.length > 0 && ( - - - - - {t("status.triggered")} ({triggeredAlerts.length}) + + + + + + + {alerts.length === 0 && ( + + + + + + {t("empty")} - - {triggeredAlerts.map((alert) => ( - - ))} - - )} + + )} - {triggeredAlerts.length > 0 && okAlerts.length > 0 && } - - {okAlerts.length > 0 && ( - - - - - {t("status.ok")} ({okAlerts.length}) - - - {okAlerts.map((alert) => ( - - ))} - - )} - - {options.showHistory && history.length > 0 && ( - <> - + {triggeredAlerts.length > 0 && ( - - - {t("history")} + + + {t("status.triggered")} ({triggeredAlerts.length}) - {history.map((entry) => { - const systemName = systemNameMap[entry.system] ?? entry.system; - const isResolved = !!entry.resolved; - const HistoryIcon = alertIconMap[entry.name] ?? Server; - return ( - - - - - - - {entry.name} - - - {systemName} + {triggeredAlerts.map((alert) => ( + + ))} + + )} + + {triggeredAlerts.length > 0 && okAlerts.length > 0 && } + + {okAlerts.length > 0 && ( + + + + + {t("status.ok")} ({okAlerts.length}) + + + {okAlerts.map((alert) => ( + + ))} + + )} + + {options.showHistory && history.length > 0 && ( + <> + + + + + + {t("history")} + + + {history.map((entry) => { + const systemName = systemNameMap[entry.system] ?? entry.system; + const isResolved = !!entry.resolved; + const HistoryIcon = alertIconMap[entry.name] ?? Server; + return ( + + + + + + + {entry.name} + + + {systemName} + + + + + + {isResolved ? t("resolved") : t("status.triggered")} + + + {dayjs(entry.created).fromNow()} - - - {isResolved ? t("resolved") : t("status.triggered")} - - - {dayjs(entry.created).fromNow()} - - - - ); - })} - - - )} - - + ); + })} + + + )} + + + ); } diff --git a/packages/widgets/src/beszel-system-grid/component.module.css b/packages/widgets/src/beszel-system-grid/component.module.css new file mode 100644 index 000000000..f70cde0e9 --- /dev/null +++ b/packages/widgets/src/beszel-system-grid/component.module.css @@ -0,0 +1,7 @@ +.clickableCard { + transition: background-color 150ms; +} + +.clickableCard:hover { + background-color: color-mix(in srgb, var(--mantine-color-default-hover) 40%, transparent) !important; +} diff --git a/packages/widgets/src/beszel-system-grid/component.tsx b/packages/widgets/src/beszel-system-grid/component.tsx index 60d367d8f..3d5c3bd42 100644 --- a/packages/widgets/src/beszel-system-grid/component.tsx +++ b/packages/widgets/src/beszel-system-grid/component.tsx @@ -1,7 +1,7 @@ "use client"; import type { MantineSize } from "@mantine/core"; -import { Badge, Box, Card, Group, Progress, Text, Stack, useComputedColorScheme } from "@mantine/core"; +import { Badge, Box, Card, Center, Group, Loader, Progress, Text, Stack } from "@mantine/core"; import { Activity, Battery, @@ -15,16 +15,22 @@ import { Thermometer, Wifi, } from "lucide-react"; +import { IconServerOff } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; +import { useModalAction } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; +import classes from "./component.module.css"; + import type { WidgetComponentProps } from "../definition"; import type { BeszelSystemRow } from "../beszel/_shared/types"; import { statusColorMap, thresholdColor } from "../beszel/_shared/colors"; import { formatByteRate, formatLoadAvg, formatPercent, formatTemp, formatUptime } from "../beszel/_shared/format"; import { useBeszelFilteredSystems, useBeszelSystemsSubscription } from "../beszel/_shared/hooks"; +import { BeszelIntegrationErrorIndicator } from "../beszel/_shared/error-indicator"; +import { BeszelSystemStatsModal } from "../beszel/_shared/system-stats-modal"; interface SizeConfig { iconSize: number; @@ -153,8 +159,8 @@ interface SystemCardProps { t: ReturnType>; size: SizeConfig; maxMetrics: number; - backgroundColor: string; itemRadius: MantineSize; + onClick?: () => void; } const metricRenderers = [ @@ -311,20 +317,23 @@ const metricRenderers = [ }, ] as const; -const SystemCard = ({ system, options, t, size, maxMetrics, backgroundColor, itemRadius }: SystemCardProps) => { +const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick }: SystemCardProps) => { const visibleMetrics = metricRenderers.filter((m) => m.visible(system, options)).slice(0, maxMetrics); return ( @@ -354,19 +363,46 @@ export default function BeszelSystemGridWidget({ }: WidgetComponentProps<"beszelSystemGrid">) { const t = useScopedI18n("widget.beszelSystemGrid"); const board = useRequiredBoard(); - const colorScheme = useComputedColorScheme("light"); - const opacity = board.opacity / 100; - const bgBase: Record<"light" | "dark", string> = { dark: "57, 57, 57", light: "246, 247, 248" }; - const backgroundColor = `rgba(${bgBase[colorScheme]}, ${opacity})`; + const { openModal } = useModalAction(BeszelSystemStatsModal); - const { data: results = [] } = clientApi.widget.beszel.getSystems.useQuery( + const { + data: results = [], + error: systemsError, + isPending, + } = clientApi.widget.beszel.getSystems.useQuery( { integrationIds }, - { staleTime: 5_000, refetchInterval: 5_000, retry: false }, + { staleTime: 10_000, gcTime: 48 * 60 * 60 * 1000, refetchInterval: 10_000, retry: false }, ); useBeszelSystemsSubscription(integrationIds, !isEditMode); const filteredSystems = useBeszelFilteredSystems(results, options.statusFilter); + if (systemsError) throw systemsError; + + if (isPending) { + return ( +
+ +
+ ); + } + + if (filteredSystems.length === 0) { + return ( + + +
+ + + + {t("empty.noSystems")} + + +
+
+ ); + } + const cols = getColCount(width, filteredSystems.length); const rows = Math.ceil(filteredSystems.length / cols) || 1; const rawCellHeight = height / rows; @@ -377,29 +413,37 @@ export default function BeszelSystemGridWidget({ const maxMetrics = getMaxVisibleMetrics(effectiveCellHeight, size); return ( - - {filteredSystems.map((system) => ( - - ))} + + + + {filteredSystems.map((system) => { + const integrationId = system._key.split(":")[0] ?? ""; + const handleClick = isEditMode + ? undefined + : () => openModal({ integrationId, systemId: system.id }, { title: system.name }); + return ( + + ); + })} + ); } diff --git a/packages/widgets/src/beszel-system-stats/component.module.css b/packages/widgets/src/beszel-system-stats/component.module.css index ca1613eef..7750108f9 100644 --- a/packages/widgets/src/beszel-system-stats/component.module.css +++ b/packages/widgets/src/beszel-system-stats/component.module.css @@ -3,4 +3,12 @@ top: 6px; left: 6px; z-index: 1; + opacity: 0; + transition: opacity 0.15s ease; + pointer-events: none; +} + +.beszelStatsContainer:hover .beszelStatsSystemToggle { + opacity: 1; + pointer-events: auto; } diff --git a/packages/widgets/src/beszel-system-stats/component.tsx b/packages/widgets/src/beszel-system-stats/component.tsx index 2c40205ed..02d77a832 100644 --- a/packages/widgets/src/beszel-system-stats/component.tsx +++ b/packages/widgets/src/beszel-system-stats/component.tsx @@ -1,8 +1,8 @@ "use client"; import { useCallback, useMemo } from "react"; -import { Button, Center, Menu, ScrollArea, Select, SimpleGrid, Stack, Text } from "@mantine/core"; -import { IconPlugConnectedX, IconServer, IconQuestionMark } from "@tabler/icons-react"; +import { Button, Box, Center, Loader, Menu, ScrollArea, Select, SimpleGrid, Stack, Text } from "@mantine/core"; +import { IconPlugConnectedX, IconServer, IconQuestionMark, IconServerOff } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; @@ -15,6 +15,7 @@ import classes from "./component.module.css"; import type { WidgetComponentProps } from "../definition"; import { containerColors } from "../beszel/_shared/colors"; +import type { BeszelTimePeriod } from "../beszel/_shared/chart"; import { BeszelChartPanel, CPU_Y_AXIS_DOMAIN, @@ -29,6 +30,7 @@ import { formatPercent, formatStorageBytes, } from "../beszel/_shared/format"; +import { BeszelIntegrationErrorIndicator } from "../beszel/_shared/error-indicator"; import { makeTooltipProps } from "../beszel/_shared/tooltip"; import { useLiveStats } from "../beszel/_shared/use-live-stats"; @@ -61,9 +63,13 @@ export default function BeszelSystemStatsWidget({ const { data: session } = useSession(); const hasChangeAccess = board ? constructBoardPermissions(board, session).hasChangeAccess : false; const { mutate: saveItemOptions } = clientApi.widget.options.saveItemOptions.useMutation(); - const { data: systemsResult = [], isPending: systemsPending } = clientApi.widget.beszel.getSystems.useQuery( + const { + data: systemsResult = [], + isPending: systemsPending, + error: systemsError, + } = clientApi.widget.beszel.getSystems.useQuery( { integrationIds }, - { staleTime: 30 * 1000 }, + { staleTime: 10_000, gcTime: 48 * 60 * 60 * 1000, retry: false }, ); const systems = useMemo( @@ -89,20 +95,26 @@ export default function BeszelSystemStatsWidget({ const showDocker = options.showDockerCpu || options.showDockerMemory || options.showDockerNetwork; const isLive = options.timePeriod === "1m"; - const { data: statsResult } = clientApi.widget.beszel.getSystemStats.useQuery( + const { data: statsResult, error: statsError } = clientApi.widget.beszel.getSystemStats.useQuery( { integrationIds, systemId: selectedSystem, timePeriod: options.timePeriod as "1m" | "1h" | "12h" | "24h" | "1w" | "30d", includeDocker: showDocker, }, - { staleTime: 30 * 1000, enabled: !isLive && systemReady && selectedSystem !== "" }, + { + staleTime: 10_000, + gcTime: 48 * 60 * 60 * 1000, + refetchInterval: isLive ? false : 10_000, + enabled: !isLive && systemReady && selectedSystem !== "", + retry: false, + }, ); const { data: liveData, error: liveError } = useLiveStats(integrationIds, selectedSystem, isLive && systemReady); let activeStats: - | { systemStats: BeszelSystemStatsRecord[]; containerStats: BeszelContainerStatsRecord[] } + | { systemStats: BeszelSystemStatsRecord[]; containerStats: BeszelContainerStatsRecord[]; error?: string } | null | undefined = statsResult; if (isLive) { @@ -152,30 +164,31 @@ export default function BeszelSystemStatsWidget({ const systemStats = activeStats?.systemStats; const containerStatsRaw = activeStats?.containerStats; - const cpuData = useSystemChartData(statsWhenShown(options.showCpu, systemStats), mappers.cpu, isLive); - const memoryData = useSystemChartData(statsWhenShown(options.showMemory, systemStats), mappers.memory, isLive); - const diskData = useSystemChartData(statsWhenShown(options.showDisk, systemStats), mappers.disk, isLive); - const diskIOData = useSystemChartData(statsWhenShown(options.showDiskIO, systemStats), mappers.diskIO, isLive); - const networkData = useSystemChartData(statsWhenShown(options.showNetwork, systemStats), mappers.network, isLive); + const timePeriod = options.timePeriod as BeszelTimePeriod; + const cpuData = useSystemChartData(statsWhenShown(options.showCpu, systemStats), mappers.cpu, timePeriod); + const memoryData = useSystemChartData(statsWhenShown(options.showMemory, systemStats), mappers.memory, timePeriod); + const diskData = useSystemChartData(statsWhenShown(options.showDisk, systemStats), mappers.disk, timePeriod); + const diskIOData = useSystemChartData(statsWhenShown(options.showDiskIO, systemStats), mappers.diskIO, timePeriod); + const networkData = useSystemChartData(statsWhenShown(options.showNetwork, systemStats), mappers.network, timePeriod); const containerNames = useContainerNames(statsWhenShown(showDocker, containerStatsRaw)); const dockerCpuData = useDockerChartData( statsWhenShown(options.showDockerCpu, containerStatsRaw), containerNames, "cpu", - isLive, + timePeriod, ); const dockerMemData = useDockerChartData( statsWhenShown(options.showDockerMemory, containerStatsRaw), containerNames, "memory", - isLive, + timePeriod, ); const dockerNetData = useDockerChartData( statsWhenShown(options.showDockerNetwork, containerStatsRaw), containerNames, "network", - isLive, + timePeriod, ); const containerSeries = useMemo( @@ -185,6 +198,33 @@ export default function BeszelSystemStatsWidget({ const cols = gridColumns[Number(width > 600)]; + if (systemsError) throw systemsError; + if (!isLive && statsError) throw statsError; + + if (systemsPending) { + return ( +
+ +
+ ); + } + + if (systems.length === 0) { + return ( + + +
+ + + + {t("empty.noSystems")} + + +
+
+ ); + } + if (!systemsPending && !systemExists && systems.length > 0) { return (
@@ -222,160 +262,186 @@ export default function BeszelSystemStatsWidget({ } return ( - - - {!isEditMode && systems.length > 1 && ( - - - - - - {systems.map((s) => ( - handleSelectSystem(s.value)} + + + + + + + {!isEditMode && systems.length > 1 && ( + + + - )} + {selectedLabel} + + + + {systems.map((s) => ( + handleSelectSystem(s.value)} + > + {s.label} + + ))} + + + )} - {activeStats && ( - - {options.showCpu && cpuData.length > 0 && ( - - )} + {!isLive && !activeStats && systemReady && selectedSystem !== "" && ( +
+ +
+ )} - {options.showMemory && memoryData.length > 0 && ( - - )} + {!isLive && activeStats && "error" in activeStats && activeStats.error && ( +
+ + + + {activeStats.error} + + +
+ )} - {options.showDisk && diskData.length > 0 && ( - - )} + {activeStats && (!("error" in activeStats) || !activeStats.error) && ( + + {options.showCpu && cpuData.length > 0 && ( + + )} - {options.showDiskIO && diskIOData.length > 0 && ( - - )} + {options.showMemory && memoryData.length > 0 && ( + + )} - {options.showNetwork && networkData.length > 0 && ( - - )} + {options.showDisk && diskData.length > 0 && ( + + )} - {showDocker && containerSeries.length > 0 && ( - <> - {options.showDockerCpu && dockerCpuData.length > 0 && ( - - )} + {options.showDiskIO && diskIOData.length > 0 && ( + + )} - {options.showDockerMemory && dockerMemData.length > 0 && ( - - )} + {options.showNetwork && networkData.length > 0 && ( + + )} - {options.showDockerNetwork && dockerNetData.length > 0 && ( - - )} - - )} - - )} -
-
+ {showDocker && containerSeries.length > 0 && ( + <> + {options.showDockerCpu && dockerCpuData.length > 0 && ( + + )} + + {options.showDockerMemory && dockerMemData.length > 0 && ( + + )} + + {options.showDockerNetwork && dockerNetData.length > 0 && ( + + )} + + )} + + )} + + + ); } diff --git a/packages/widgets/src/beszel-system-table/component.tsx b/packages/widgets/src/beszel-system-table/component.tsx index 43d640b0f..1d8c92355 100644 --- a/packages/widgets/src/beszel-system-table/component.tsx +++ b/packages/widgets/src/beszel-system-table/component.tsx @@ -3,7 +3,7 @@ import "./styles.css"; import { useMemo, useState } from "react"; -import { Group, Indicator, Progress, Text } from "@mantine/core"; +import { Center, Group, Indicator, Loader, Progress, Text } from "@mantine/core"; import type { DataTableColumn, DataTableSortStatus } from "mantine-datatable"; import { DataTable } from "mantine-datatable"; import { @@ -20,6 +20,7 @@ import { } from "lucide-react"; import { clientApi } from "@homarr/api/client"; +import { useModalAction } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; @@ -27,6 +28,8 @@ import type { BeszelSystemRow } from "../beszel/_shared/types"; import { loadAvgColor, statusColorMap, thresholdColor } from "../beszel/_shared/colors"; import { formatByteRate, formatLoadAvg, formatPercent, formatTemp, formatUptime } from "../beszel/_shared/format"; import { useBeszelFilteredSystems, useBeszelSystemsSubscription } from "../beszel/_shared/hooks"; +import { BeszelIntegrationErrorIndicator } from "../beszel/_shared/error-indicator"; +import { BeszelSystemStatsModal } from "../beszel/_shared/system-stats-modal"; const directionMultiplier: Record = { asc: 1, desc: -1 }; @@ -66,9 +69,14 @@ export default function BeszelSystemTableWidget({ width, }: WidgetComponentProps<"beszelSystemTable">) { const t = useScopedI18n("widget.beszelSystemTable"); - const { data: results = [] } = clientApi.widget.beszel.getSystems.useQuery( + const { openModal } = useModalAction(BeszelSystemStatsModal); + const { + data: results = [], + error: systemsError, + isPending, + } = clientApi.widget.beszel.getSystems.useQuery( { integrationIds }, - { staleTime: 5_000, refetchInterval: 5_000, retry: false }, + { staleTime: 10_000, gcTime: 48 * 60 * 60 * 1000, refetchInterval: 10_000, retry: false }, ); const size = getSizeConfig(width); @@ -255,21 +263,42 @@ export default function BeszelSystemTableWidget({ return cols.filter(Boolean) as DataTableColumn[]; }, [options, t, size]); + const handleRowClick = ({ record }: { record: SystemRowWithKey }) => { + const integrationId = record._key.split(":")[0] ?? ""; + openModal({ integrationId, systemId: record.id }, { title: record.name }); + }; + + if (systemsError) throw systemsError; + + if (isPending) { + return ( +
+ +
+ ); + } + return ( - +
+
+ +
+ +
); } diff --git a/packages/widgets/src/beszel-system-table/styles.css b/packages/widgets/src/beszel-system-table/styles.css index 9b4550701..cdfd682f9 100644 --- a/packages/widgets/src/beszel-system-table/styles.css +++ b/packages/widgets/src/beszel-system-table/styles.css @@ -1,5 +1,28 @@ +/* Make the DataTable transparent so the board card's opacity-controlled + background shows through. The mantine-datatable defaults to + var(--mantine-color-body) which is opaque. */ +.beszel-table, +.beszel-table .mantine-datatable-table, +.beszel-table .mantine-datatable-table thead, +.beszel-table .mantine-datatable-table tbody, +.beszel-table .mantine-datatable-table tfoot, +.beszel-table th, +.beszel-table td { + background-color: transparent !important; +} + +.beszel-table .mantine-datatable-table tr { + background-color: transparent; +} + +.beszel-table .mantine-datatable-table tbody tr:hover { + background-color: color-mix(in srgb, var(--mantine-color-default-hover) 40%, transparent) !important; +} + .beszel-table th { white-space: nowrap; + background-color: color-mix(in srgb, var(--mantine-color-body) 60%, transparent) !important; + backdrop-filter: blur(8px); } .beszel-table td { diff --git a/packages/widgets/src/beszel/_shared/chart.tsx b/packages/widgets/src/beszel/_shared/chart.tsx index 3938188f1..8d8a5e319 100644 --- a/packages/widgets/src/beszel/_shared/chart.tsx +++ b/packages/widgets/src/beszel/_shared/chart.tsx @@ -8,18 +8,50 @@ import dayjs from "dayjs"; import type { BeszelContainerStatsRecord, BeszelSystemStatsRecord } from "@homarr/integrations/types"; -const formatTime = (timestamp: string) => dayjs(timestamp).format("HH:mm"); -const formatTimeLive = (timestamp: string) => dayjs(timestamp).format("HH:mm:ss"); +export type BeszelTimePeriod = "1m" | "1h" | "12h" | "24h" | "1w" | "30d"; -function prepareRecords(records: T[], live: boolean) { - if (live) { - return { fmt: formatTimeLive, ordered: records }; +const timeFormats: Record = { + "1m": "HH:mm:ss", + "1h": "HH:mm", + "12h": "HH:mm", + "24h": "HH:mm", + "1w": "MMM D", + "30d": "MMM D", +}; + +const periodDays: Partial> = { "1w": 7, "30d": 30 }; + +function prepareRecords(records: T[], timePeriod: BeszelTimePeriod) { + const fmt = (timestamp: string) => dayjs(timestamp).format(timeFormats[timePeriod]); + if (timePeriod === "1m") { + return { fmt, ordered: records }; } - return { fmt: formatTime, ordered: [...records].toReversed() }; + return { fmt, ordered: [...records].toReversed() }; +} + +function padTimeGrid(data: Record[], timePeriod: BeszelTimePeriod) { + const days = periodDays[timePeriod]; + if (!days) return data; + + const fmt = (ts: string) => dayjs(ts).format(timeFormats[timePeriod]); + const now = dayjs(); + const existingDays = new Set(data.map((d) => dayjs(d.rawTime as string).format("YYYY-MM-DD"))); + const result = [...data]; + + for (let i = days; i >= 0; i--) { + const d = now.subtract(i, "day").startOf("day"); + const key = d.format("YYYY-MM-DD"); + if (!existingDays.has(key)) { + const iso = d.toISOString(); + result.push({ time: fmt(iso), rawTime: iso }); + } + } + + return result.toSorted((a, b) => new Date(a.rawTime as string).getTime() - new Date(b.rawTime as string).getTime()); } const yAxisBase = { tickMargin: 0, tick: { fontSize: 10 } } as const; -const chartStyle = { minWidth: 0, minHeight: 0 } as const; +const chartStyle = { minWidth: 0, minHeight: 1 } as const; const panelStyle = { minWidth: 0, overflow: "hidden" } as const; export const CPU_Y_AXIS_DOMAIN: [number, string] = [0, "auto"]; @@ -77,7 +109,7 @@ const BeszelAreaChart = memo( dataKey="time" curveType="monotone" withGradient={false} - connectNulls + connectNulls={false} withDots={false} type={type} strokeWidth={1} @@ -96,16 +128,18 @@ const BeszelAreaChart = memo( export const useSystemChartData = ( systemStats: BeszelSystemStatsRecord[] | undefined, mapFn: (stats: BeszelSystemStatsRecord["stats"]) => Record, - live = false, + timePeriod: BeszelTimePeriod = "1h", ) => useMemo(() => { if (!systemStats) return []; - const { fmt, ordered } = prepareRecords(systemStats, live); - return ordered.map((r) => ({ + const { fmt, ordered } = prepareRecords(systemStats, timePeriod); + const mapped = ordered.map((r) => ({ time: fmt(r.created), + rawTime: r.created, ...mapFn(r.stats), })); - }, [systemStats, mapFn, live]); + return padTimeGrid(mapped, timePeriod); + }, [systemStats, mapFn, timePeriod]); export const useContainerNames = (containerStats: BeszelContainerStatsRecord[] | undefined, max = 15) => { const prevRef = useRef([]); @@ -144,19 +178,20 @@ export const useDockerChartData = ( containerStats: BeszelContainerStatsRecord[] | undefined, containerNames: string[], metric: "cpu" | "memory" | "network", - live = false, + timePeriod: BeszelTimePeriod = "1h", ) => useMemo(() => { if (!containerStats?.length) return []; const extract = defaultContainerExtractors[metric]; if (!extract) return []; - const { fmt, ordered } = prepareRecords(containerStats, live); - return ordered.map((record) => { - const point: Record = { time: fmt(record.created) }; + const { fmt, ordered } = prepareRecords(containerStats, timePeriod); + const mapped = ordered.map((record) => { + const point: Record = { time: fmt(record.created), rawTime: record.created }; const byName = new Map(record.stats.map((c) => [c.n, c])); for (const name of containerNames) { point[name] = extract(byName.get(name)); } return point; }); - }, [containerStats, containerNames, metric, live]); + return padTimeGrid(mapped, timePeriod); + }, [containerStats, containerNames, metric, timePeriod]); diff --git a/packages/widgets/src/beszel/_shared/error-indicator.tsx b/packages/widgets/src/beszel/_shared/error-indicator.tsx new file mode 100644 index 000000000..7d539baac --- /dev/null +++ b/packages/widgets/src/beszel/_shared/error-indicator.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { Tooltip } from "@mantine/core"; +import { IconAlertTriangle } from "@tabler/icons-react"; + +interface IntegrationResult { + integrationId: string; + integrationName?: string; + error?: string; +} + +interface BeszelIntegrationErrorIndicatorProps { + results: IntegrationResult[]; +} + +export function BeszelIntegrationErrorIndicator({ results }: BeszelIntegrationErrorIndicatorProps) { + const failed = results.filter((r) => "error" in r && r.error); + if (failed.length === 0) return null; + const label = failed.map((r) => r.integrationName ?? r.integrationId).join(", "); + return ( + + + + ); +} diff --git a/packages/widgets/src/beszel/_shared/hooks.ts b/packages/widgets/src/beszel/_shared/hooks.ts index 9d48256af..ebb84b4eb 100644 --- a/packages/widgets/src/beszel/_shared/hooks.ts +++ b/packages/widgets/src/beszel/_shared/hooks.ts @@ -31,7 +31,10 @@ export const useBeszelFilteredSystems = ( statusFilter: string, ): SystemRowWithKey[] => { const allSystems = useMemo( - () => results.flatMap((r) => r.systems.map((s) => ({ ...s, _key: `${r.integrationId}:${s.id}` }))), + () => + results + .flatMap((r) => r.systems.map((s) => ({ ...s, _key: `${r.integrationId}:${s.id}` }))) + .toSorted((a, b) => a.name.localeCompare(b.name)), [results], ); diff --git a/packages/widgets/src/beszel/_shared/system-stats-modal.tsx b/packages/widgets/src/beszel/_shared/system-stats-modal.tsx new file mode 100644 index 000000000..52781c5af --- /dev/null +++ b/packages/widgets/src/beszel/_shared/system-stats-modal.tsx @@ -0,0 +1,173 @@ +"use client"; + +import { useMemo, useState } from "react"; +import { SegmentedControl, SimpleGrid, Stack } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import { createModal } from "@homarr/modals"; +import { useScopedI18n } from "@homarr/translation/client"; + +import type { BeszelTimePeriod } from "./chart"; +import { BeszelChartPanel, CPU_Y_AXIS_DOMAIN, useSystemChartData } from "./chart"; +import { chartAxisFormatters, formatByteRate, formatGB, formatPercent } from "./format"; +import { makeTooltipProps } from "./tooltip"; + +const tooltipPercent = makeTooltipProps(formatPercent); +const tooltipGB = makeTooltipProps(formatGB, true); +const tooltipRate = makeTooltipProps(formatByteRate, true); + +const CHART_HEIGHT = 180; +const MB = 1024 * 1024; + +const timePeriodOptions: { value: BeszelTimePeriod; label: string }[] = [ + { value: "1h", label: "1H" }, + { value: "12h", label: "12H" }, + { value: "24h", label: "24H" }, + { value: "1w", label: "1W" }, + { value: "30d", label: "30D" }, +]; + +interface BeszelSystemStatsModalProps { + integrationId: string; + systemId: string; +} + +export const BeszelSystemStatsModal = createModal(({ innerProps }) => { + const t = useScopedI18n("widget.beszelSystemStats"); + const [timePeriod, setTimePeriod] = useState("1h"); + + const { data } = clientApi.widget.beszel.getSystemStats.useQuery( + { + integrationIds: [innerProps.integrationId], + systemId: innerProps.systemId, + timePeriod, + includeDocker: false, + }, + { staleTime: 10_000, gcTime: 48 * 60 * 60 * 1000, refetchInterval: 10_000 }, + ); + + const mappers = useMemo( + () => ({ + cpu: (s: { cpu: number }) => ({ [t("chart.cpu.series")]: s.cpu }), + memory: (s: { mu: number; mb: number }) => ({ + [t("chart.memory.series")]: s.mu, + [t("chart.memory.cache")]: s.mb ?? 0, + }), + disk: (s: { du: number }) => ({ [t("chart.disk.series")]: s.du }), + diskIO: (s: { dr?: number; dw?: number }) => ({ + [t("chart.diskIO.read")]: (s.dr ?? 0) * MB, + [t("chart.diskIO.write")]: (s.dw ?? 0) * MB, + }), + network: (s: { ns: number; nr: number; b?: [number, number] }) => ({ + [t("chart.network.sent")]: s.b?.[0] ?? s.ns, + [t("chart.network.recv")]: s.b?.[1] ?? s.nr, + }), + }), + [t], + ); + + const series = useMemo( + () => ({ + cpu: [{ name: t("chart.cpu.series"), color: "teal.6" }], + memory: [ + { name: t("chart.memory.series"), color: "teal.5" }, + { name: t("chart.memory.cache"), color: "teal.8" }, + ], + disk: [{ name: t("chart.disk.series"), color: "grape.6" }], + diskIO: [ + { name: t("chart.diskIO.write"), color: "orange.6" }, + { name: t("chart.diskIO.read"), color: "blue.6" }, + ], + network: [ + { name: t("chart.network.sent"), color: "blue.6" }, + { name: t("chart.network.recv"), color: "teal.6" }, + ], + }), + [t], + ); + + const systemStats = data?.systemStats; + const cpuData = useSystemChartData(systemStats, mappers.cpu, timePeriod); + const memoryData = useSystemChartData(systemStats, mappers.memory, timePeriod); + const diskData = useSystemChartData(systemStats, mappers.disk, timePeriod); + const diskIOData = useSystemChartData(systemStats, mappers.diskIO, timePeriod); + const networkData = useSystemChartData(systemStats, mappers.network, timePeriod); + + return ( + + setTimePeriod(v as BeszelTimePeriod)} + data={timePeriodOptions} + /> + + {cpuData.length > 0 && ( + + )} + {memoryData.length > 0 && ( + + )} + {diskData.length > 0 && ( + + )} + {diskIOData.length > 0 && ( + + )} + {networkData.length > 0 && ( + + )} + + + ); +}).withOptions({ + defaultTitle: (t) => t("widget.beszelSystemStats.name"), + size: 1200, +}); diff --git a/packages/widgets/src/beszel/_shared/tooltip.tsx b/packages/widgets/src/beszel/_shared/tooltip.tsx index a670af67d..b43ea1765 100644 --- a/packages/widgets/src/beszel/_shared/tooltip.tsx +++ b/packages/widgets/src/beszel/_shared/tooltip.tsx @@ -3,6 +3,10 @@ import type { CSSProperties } from "react"; import { createPortal } from "react-dom"; import { useCallback, useEffect, useRef, useState } from "react"; +import dayjs from "dayjs"; +import localizedFormat from "dayjs/plugin/localizedFormat"; + +dayjs.extend(localizedFormat); const styles: Record = { wrapper: { @@ -40,6 +44,7 @@ export interface TooltipPayloadItem { value: number; color: string; dataKey: string; + payload?: Record; } interface PortalTooltipProps { @@ -50,16 +55,39 @@ interface PortalTooltipProps { showTotal?: boolean; } +const MARGIN = 14; + const PortalTooltipContent = ({ active, label, payload, formatter, showTotal }: PortalTooltipProps) => { const mouseRef = useRef({ x: 0, y: 0 }); - const [mouse, setMouse] = useState({ x: 0, y: 0 }); + const [pos, setPos] = useState({ x: 0, y: 0 }); const rafRef = useRef(0); + const tooltipRef = useRef(null); const handleMouse = useCallback((e: MouseEvent) => { mouseRef.current = { x: e.clientX, y: e.clientY }; cancelAnimationFrame(rafRef.current); rafRef.current = requestAnimationFrame(() => { - setMouse(mouseRef.current); + const el = tooltipRef.current; + const mx = mouseRef.current.x; + const my = mouseRef.current.y; + + if (!el) { + setPos({ x: mx + MARGIN, y: my }); + return; + } + + const { width, height } = el.getBoundingClientRect(); + const vw = window.innerWidth; + const vh = window.innerHeight; + + let x = mx + MARGIN; + let y = my - height / 2; + + if (x + width > vw - MARGIN) x = mx - width - MARGIN; + if (y < MARGIN) y = MARGIN; + if (y + height > vh - MARGIN) y = vh - MARGIN - height; + + setPos({ x, y }); }); }, []); @@ -84,21 +112,22 @@ const PortalTooltipContent = ({ active, label, payload, formatter, showTotal }: if (!sorted.length) return null; + const rawTime = sorted[0]?.payload?.rawTime as string | undefined; + const tooltipLabel = rawTime ? dayjs(rawTime).format("MMM D, LT") : label; const total = sorted.reduce((sum, p) => sum + p.value, 0); const portalStyle: CSSProperties = { position: "fixed", - left: mouse.x + 14, - top: mouse.y, - transform: "translateY(-50%)", + left: pos.x, + top: pos.y, zIndex: 10000, pointerEvents: "none", }; return createPortal( -
+
-
{label}
+
{tooltipLabel}
{sorted.map((item) => (
diff --git a/packages/widgets/src/docker/component.tsx b/packages/widgets/src/docker/component.tsx index b50139361..d6c1d004d 100644 --- a/packages/widgets/src/docker/component.tsx +++ b/packages/widgets/src/docker/component.tsx @@ -207,7 +207,7 @@ export default function DockerWidget({ options, width, isEditMode }: WidgetCompo acc.memory += safeValue(container.memoryUsage); return acc; }, - { cpu: 0, memory: 0 } + { cpu: 0, memory: 0 }, ); }, [containers]); @@ -283,7 +283,7 @@ export default function DockerWidget({ options, width, isEditMode }: WidgetCompo {t("table.totalCpu", { cpu: totals.cpu.toFixed(2) })} - + {t("table.totalMemory", { memory: humanFileSize(totals.memory) })} diff --git a/packages/widgets/src/health-monitoring/index.ts b/packages/widgets/src/health-monitoring/index.ts index 698446c28..dd176a189 100644 --- a/packages/widgets/src/health-monitoring/index.ts +++ b/packages/widgets/src/health-monitoring/index.ts @@ -95,6 +95,12 @@ export const { definition, componentLoader } = createWidgetDefinition("healthMon return !integrationKinds.includes("proxmox"); }, }, + defaultTab: { + shouldHide(_, integrationKinds) { + // The system/cluster tabs only render for Proxmox, so the default tab choice does nothing otherwise + return !integrationKinds.includes("proxmox"); + }, + }, }, ); }, diff --git a/packages/widgets/src/health-monitoring/system-health.tsx b/packages/widgets/src/health-monitoring/system-health.tsx index 1f0dd02e5..405838cac 100644 --- a/packages/widgets/src/health-monitoring/system-health.tsx +++ b/packages/widgets/src/health-monitoring/system-health.tsx @@ -13,7 +13,6 @@ import { Progress, Stack, Text, - Tooltip, } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { @@ -33,6 +32,7 @@ import duration from "dayjs/plugin/duration"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; +import { humanFileSize } from "@homarr/common"; import type { TranslationFunction } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; @@ -91,7 +91,7 @@ export const SystemHealthMonitoring = ({ return ( - {healthData.map(({ integrationId, integrationName, healthInfo, updatedAt }) => { + {healthData.map(({ integrationId, integrationName, healthInfo }) => { const disksData = matchFileSystemAndSmart(healthInfo.fileSystem, healthInfo.smart); const memoryUsage = formatMemoryUsage(healthInfo.memAvailableInBytes, healthInfo.memUsedInBytes); return ( @@ -196,11 +196,6 @@ export const SystemHealthMonitoring = ({ ))} - { - - {t("widget.healthMonitoring.popover.lastSeen", { lastSeen: dayjs(updatedAt).fromNow() })} - - } {options.fileSystem && disksData.map((disk) => { return ( @@ -214,7 +209,7 @@ export const SystemHealthMonitoring = ({ radius={board.itemRadius} p="xs" > - + - - - - {options.fahrenheit - ? `${(disk.temperature * 1.8 + 32).toFixed(1)}°F` - : `${disk.temperature}°C`} - - + {disk.temperature !== null && ( + + + + {options.fahrenheit + ? `${(disk.temperature * 1.8 + 32).toFixed(1)}°F` + : `${disk.temperature}°C`} + + + )} @@ -243,37 +240,26 @@ export const SystemHealthMonitoring = ({ - - - - - {t("widget.healthMonitoring.popover.used")} - - - - - = 1 - ? `${(Number(disk.available) / 1024 ** 4).toFixed(2)} TiB` - : `${(Number(disk.available) / 1024 ** 3).toFixed(2)} GiB` - } - > - - - {t("widget.healthMonitoring.popover.available")} - - - + + + + + + {t("widget.healthMonitoring.popover.used")} {formatFileSize(disk.used)} + + + {formatFileSize(disk.available)} {t("widget.healthMonitoring.popover.available")} + + ); @@ -307,6 +293,13 @@ export const progressColor = (percentage: number) => { else return "red"; }; +// Some integrations report file sizes as raw bytes (e.g. TrueNAS, Glances) while others pre-format +// them (e.g. Unraid, dashdot). Format the former and pass the latter through untouched. +const formatFileSize = (value: string) => { + const bytes = Number(value); + return Number.isFinite(bytes) ? humanFileSize(Math.round(bytes)) : value; +}; + interface FileSystem { deviceName: string; used: string; @@ -331,7 +324,7 @@ export const matchFileSystemAndSmart = (fileSystems: FileSystem[], smartData: Sm used: fileSystem.used, available: fileSystem.available, percentage: fileSystem.percentage, - temperature: smartDisk?.temperature ?? 0, + temperature: smartDisk?.temperature ?? null, overallStatus: smartDisk?.overallStatus ?? "", }; }) diff --git a/packages/widgets/src/index.tsx b/packages/widgets/src/index.tsx index 628c67e32..17e9b8eed 100644 --- a/packages/widgets/src/index.tsx +++ b/packages/widgets/src/index.tsx @@ -52,6 +52,7 @@ import * as timetable from "./timetable"; import * as tracearr from "./tracearr"; import * as umami from "./umami"; import * as ups from "./ups"; +import * as vpn from "./vpn"; import * as beszelSystemTable from "./beszel-system-table"; import * as beszelSystemGrid from "./beszel-system-grid"; import * as beszelAlerts from "./beszel-alerts"; @@ -108,6 +109,7 @@ export const widgetImports = { uptimeKuma, audioStats, umami, + vpn, ups, beszelSystemTable, beszelSystemGrid, diff --git a/packages/widgets/src/system-disks/component.tsx b/packages/widgets/src/system-disks/component.tsx index 5c6271c09..efe2fe73d 100644 --- a/packages/widgets/src/system-disks/component.tsx +++ b/packages/widgets/src/system-disks/component.tsx @@ -1,6 +1,7 @@ "use client"; -import { Box, Card, Group, Stack, useMantineColorScheme } from "@mantine/core"; +import { useEffect, useRef, useState } from "react"; +import { Box, Card, Group, Stack, Tooltip, useMantineColorScheme } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; @@ -31,6 +32,90 @@ const getDisplayText = (item: { used: string; available: string; percentage: num } }; +interface SystemDiskCardProps { + deviceName: string; + percentage: number; + displayText: string; + temperature: number | null | undefined; + healthy: boolean; + showBackgroundBar: boolean; +} + +const SystemDiskCard = ({ + deviceName, + percentage, + displayText, + temperature, + healthy, + showBackgroundBar, +}: SystemDiskCardProps) => { + const board = useRequiredBoard(); + const scheme = useMantineColorScheme(); + const t = useI18n(); + const valueRef = useRef(null); + const [valueFits, setValueFits] = useState(true); + + // When the card is squeezed (small widget), the value line is clipped by the card's `overflow: hidden`. + // Detect that and hide it, surfacing the value in a tooltip instead. The value keeps its layout space + // (visibility, not display) so toggling it does not change the measurement and flap. The ref lives on + // the value (not the Card) so the Tooltip can attach its own ref to the Card. + useEffect(() => { + const value = valueRef.current; + const card = value?.offsetParent as HTMLElement | null; // the position:relative Card + if (!value || !card) return; + const measure = () => { + setValueFits(value.getBoundingClientRect().bottom <= card.getBoundingClientRect().bottom + 1); + }; + measure(); + const observer = new ResizeObserver(measure); + observer.observe(card); + return () => observer.disconnect(); + }, [displayText, healthy]); + + const unhealthyLabel = t("widget.systemDisks.status.unhealthy"); + + return ( + + + +
+

+ {deviceName} +

+

+ {displayText} + {!healthy && {unhealthyLabel}} +

+
+
{temperature ?

{temperature}°C

: null}
+
+ +
+
+ ); +}; + export default function SystemResources({ integrationIds, options }: WidgetComponentProps<"systemDisks">) { const queryInput = { integrationIds }; const { data = [] } = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery(queryInput, { @@ -38,10 +123,6 @@ export default function SystemResources({ integrationIds, options }: WidgetCompo }); const utils = clientApi.useUtils(); - const board = useRequiredBoard(); - const scheme = useMantineColorScheme(); - const t = useI18n(); - clientApi.widget.healthMonitoring.subscribeSystemHealthStatus.useSubscription(queryInput, { onData(data) { utils.widget.healthMonitoring.getSystemHealthStatus.setData(queryInput, (oldData) => @@ -63,45 +144,17 @@ export default function SystemResources({ integrationIds, options }: WidgetCompo {fileSystem.map((item) => { const smartItem = smart.find((smart) => smart.deviceName === item.deviceName); - const healthy = smartItem?.healthy ?? true; // fall back to healthy if no information is available return ( - - -
-

- {item.deviceName} -

-

- {getDisplayText(item, options.displayMode)} - {!healthy && {t("widget.systemDisks.status.unhealthy")}} -

-
-
- {smartItem?.temperature && options.showTemperatureIfAvailable ? ( -

{smartItem.temperature}°C

- ) : null} -
-
- -
+ deviceName={item.deviceName} + percentage={item.percentage} + displayText={getDisplayText(item, options.displayMode)} + temperature={options.showTemperatureIfAvailable ? smartItem?.temperature : undefined} + healthy={smartItem?.healthy ?? true} // fall back to healthy if no information is available + showBackgroundBar={options.showBackgroundBar} + /> ); })}
diff --git a/packages/widgets/src/vpn/component.tsx b/packages/widgets/src/vpn/component.tsx new file mode 100644 index 000000000..85ee4e3cf --- /dev/null +++ b/packages/widgets/src/vpn/component.tsx @@ -0,0 +1,72 @@ +"use client"; + +import React from "react"; +import { Flex, ScrollArea, Stack } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; + +import type { WidgetComponentProps } from "../definition"; +import { updateVpnInfoFromSubscription } from "./helpers"; +import { VpnIntegrationCard } from "./vpn-card"; + +export default function VpnWidget({ options, integrationIds }: WidgetComponentProps<"vpn">) { + const [integrations] = clientApi.widget.vpn.getSummaries.useSuspenseQuery( + { + ...options, + integrationIds, + }, + { + // Initial load only. Live updates arrive via the subscription below, which is + // fed by the VPN cron job publishing to the integration channel. + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + }, + ); + const utils = clientApi.useUtils(); + + clientApi.widget.vpn.subscribeSummaries.useSubscription( + { + integrationIds, + }, + { + onData: (data) => { + utils.widget.vpn.getSummaries.setData( + { + ...options, + integrationIds, + }, + (prevData) => updateVpnInfoFromSubscription(prevData, data), + ); + }, + }, + ); + + if (integrations.length === 1) { + // It will always have at least one integration as otherwise the NoIntegrationSelectedError would be thrown in item-content.tsx + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const vpn = integrations[0]!; + + return ( + + + + ); + } + + return ( + + + {integrations.map((vpn) => ( + + ))} + + + ); +} diff --git a/packages/widgets/src/vpn/helpers.ts b/packages/widgets/src/vpn/helpers.ts new file mode 100644 index 000000000..24a81720b --- /dev/null +++ b/packages/widgets/src/vpn/helpers.ts @@ -0,0 +1,22 @@ +import type { RouterOutputs } from "@homarr/api"; + +export const RUNNING_STATUS = "running"; + +type VpnInfoItem = RouterOutputs["widget"]["vpn"]["getSummaries"][number]; + +export function getStatusColor(status: string) { + return status === RUNNING_STATUS ? "green" : "red"; +} + +export function updateVpnInfoFromSubscription( + prevData: VpnInfoItem[] | undefined, + data: { integration: { id: string }; summary: VpnInfoItem["summary"] }, +): VpnInfoItem[] | undefined { + if (!prevData) { + return undefined; + } + + return prevData.map((item) => + item.integration.id === data.integration.id ? { ...item, summary: data.summary } : item, + ); +} diff --git a/packages/widgets/src/vpn/index.ts b/packages/widgets/src/vpn/index.ts new file mode 100644 index 000000000..426366a66 --- /dev/null +++ b/packages/widgets/src/vpn/index.ts @@ -0,0 +1,14 @@ +import { IconShieldLock } from "@tabler/icons-react"; + +import { getIntegrationKindsByCategory } from "@homarr/definitions"; + +import { createWidgetDefinition } from "../definition"; +import { optionsBuilder } from "../options"; + +export const { componentLoader, definition } = createWidgetDefinition("vpn", { + icon: IconShieldLock, + createOptions() { + return optionsBuilder.from(() => ({})); + }, + supportedIntegrations: getIntegrationKindsByCategory("vpn"), +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/vpn/vpn-card.tsx b/packages/widgets/src/vpn/vpn-card.tsx new file mode 100644 index 000000000..3cb26bdd5 --- /dev/null +++ b/packages/widgets/src/vpn/vpn-card.tsx @@ -0,0 +1,164 @@ +"use client"; + +import React from "react"; +import { Badge, Box, Card, Flex, Group, Text } from "@mantine/core"; +import { IconArrowsExchange, IconMapPin, IconShieldCheck, IconShieldX } from "@tabler/icons-react"; + +import type { RouterOutputs } from "@homarr/api"; +import { useRequiredBoard } from "@homarr/boards/context"; +import { useScopedI18n } from "@homarr/translation/client"; + +import { getStatusColor, RUNNING_STATUS } from "./helpers"; + +export type VpnInfo = RouterOutputs["widget"]["vpn"]["getSummaries"][number]["summary"]; + +export function VpnIntegrationCard({ + vpn, + integrationName, + variant = "single", +}: { + vpn: VpnInfo; + integrationName?: string; + variant?: "single" | "list"; +}) { + const board = useRequiredBoard(); + const compact = variant === "list"; + + const content = vpn ? ( + + + + + ) : ( + + ); + + if (compact) { + return ( + + {content} + + ); + } + + return {content}; +} + +function VpnUnavailableContent({ compact, integrationName }: { compact: boolean; integrationName?: string }) { + const t = useScopedI18n("widget.vpn"); + + return ( + + {/* Empty statuses render the shield and DNS badge in red (see getStatusColor). */} + + + {integrationName ? ( + + {integrationName} + + ) : null} + + {t("serviceUnavailable")} + + + + ); +} + +function VpnStatusColumn({ + vpnStatus, + dnsStatus, + compact, +}: { + vpnStatus: string; + dnsStatus: string; + compact: boolean; +}) { + // Connected shows a shield with a check; anything else (stopped or unavailable) shows a shield with a cross. + const ShieldIcon = vpnStatus === RUNNING_STATUS ? IconShieldCheck : IconShieldX; + + return ( + + + + + ); +} + +function VpnInfoColumn({ + integrationName, + publicIp, + city, + country, + provider, + protocol, + compact, +}: { + integrationName?: string; + publicIp: string; + city: string; + country: string; + provider: string; + protocol: string; + compact: boolean; +}) { + return ( + + {integrationName ? ( + + {integrationName} + + ) : null} + + {publicIp} + + + + + {city}, {country} + + + + + ); +} + +function VpnProviderDetails({ provider, protocol }: { provider: string; protocol: string }) { + return ( + + + {provider} + + + + {protocol} + + + ); +} + +function StatusDot({ status, size = 10 }: { status: string; size?: number }) { + return ; +} + +function DnsStatusBadge({ status }: { status: string }) { + return ( + } + > + DNS + + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0fd764733..682dce7d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ catalogs: specifier: ^8.0.0 version: 8.0.0 '@ctrl/qbittorrent': - specifier: ^9.12.2 - version: 9.12.2 + specifier: ^9.14.0 + version: 9.14.0 '@ctrl/transmission': specifier: ^7.4.0 version: 7.4.0 @@ -40,8 +40,8 @@ catalogs: specifier: 7.2.1 version: 7.2.1 '@gfazioli/mantine-onboarding-tour': - specifier: ^4.0.4 - version: 4.0.4 + specifier: ^4.0.5 + version: 4.0.5 '@gitbeaker/rest': specifier: ^43.8.0 version: 43.8.0 @@ -61,38 +61,38 @@ catalogs: specifier: ^1.4.0 version: 1.4.0 '@mantine/charts': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/colors-generator': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/core': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/dates': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/dropzone': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/form': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/hooks': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/modals': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/notifications': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/spotlight': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@mantine/tiptap': - specifier: ^9.3.1 - version: 9.3.1 + specifier: ^9.3.2 + version: 9.3.2 '@modelcontextprotocol/sdk': specifier: 1.29.0 version: 1.29.0 @@ -103,11 +103,11 @@ catalogs: specifier: ^3.3.0 version: 3.3.0 '@playwright/test': - specifier: ^1.60.0 - version: 1.60.0 + specifier: ^1.61.0 + version: 1.61.0 '@scalar/api-reference-react': - specifier: ^0.9.46 - version: 0.9.46 + specifier: ^0.9.47 + version: 0.9.47 '@semantic-release/changelog': specifier: ^6.0.3 version: 6.0.3 @@ -145,62 +145,62 @@ catalogs: specifier: ^5.101.0 version: 5.101.0 '@testcontainers/mysql': - specifier: ^12.0.2 - version: 12.0.2 + specifier: ^12.0.3 + version: 12.0.3 '@testcontainers/postgresql': - specifier: ^12.0.2 - version: 12.0.2 + specifier: ^12.0.3 + version: 12.0.3 '@testcontainers/redis': - specifier: ^12.0.2 - version: 12.0.2 + specifier: ^12.0.3 + version: 12.0.3 '@tiptap/extension-color': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-highlight': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-image': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-link': - specifier: ^3.26.1 - version: 3.26.1 + specifier: ^3.27.1 + version: 3.27.1 '@tiptap/extension-placeholder': - specifier: ^3.26.1 - version: 3.26.1 + specifier: ^3.27.1 + version: 3.27.1 '@tiptap/extension-table': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-table-cell': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-table-header': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-table-row': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-task-item': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-task-list': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-text-align': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-text-style': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/extension-underline': - specifier: 3.26.1 - version: 3.26.1 + specifier: 3.27.1 + version: 3.27.1 '@tiptap/react': - specifier: ^3.26.1 - version: 3.26.1 + specifier: ^3.27.1 + version: 3.27.1 '@tiptap/starter-kit': - specifier: ^3.26.1 - version: 3.26.1 + specifier: ^3.27.1 + version: 3.27.1 '@trpc/client': specifier: ^11.17.0 version: 11.17.0 @@ -274,11 +274,11 @@ catalogs: specifier: ^6.0.2 version: 6.0.2 '@vitest/coverage-v8': - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^4.1.9 + version: 4.1.9 '@vitest/ui': - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^4.1.9 + version: 4.1.9 '@xterm/addon-canvas': specifier: ^0.7.0 version: 0.7.0 @@ -358,8 +358,8 @@ catalogs: specifier: ^0.28.0 version: 0.28.0 fast-xml-parser: - specifier: ^5.8.0 - version: 5.8.0 + specifier: ^5.9.3 + version: 5.9.3 fastify: specifier: ^5.8.5 version: 5.8.5 @@ -376,8 +376,8 @@ catalogs: specifier: 5.11.1 version: 5.11.1 isomorphic-dompurify: - specifier: ^3.17.0 - version: 3.17.0 + specifier: ^3.18.0 + version: 3.18.0 jotai: specifier: ^2.20.1 version: 2.20.1 @@ -400,11 +400,11 @@ catalogs: specifier: ^4.5.0 version: 4.5.0 lucide-react: - specifier: ^1.18.0 - version: 1.18.0 + specifier: ^1.21.0 + version: 1.21.0 mantine-datatable: - specifier: ^9.3.0 - version: 9.3.0 + specifier: ^9.3.1 + version: 9.3.1 mantine-react-table: specifier: npm:mantine-react-table-open@9.0.3 version: 9.0.3 @@ -433,22 +433,22 @@ catalogs: specifier: ^5.0.5 version: 5.0.5 oxfmt: - specifier: ^0.54.0 - version: 0.54.0 + specifier: ^0.55.0 + version: 0.55.0 oxlint: - specifier: ^1.69.0 - version: 1.69.0 + specifier: ^1.70.0 + version: 1.70.0 pg: - specifier: ^8.21.0 - version: 8.21.0 + specifier: ^8.22.0 + version: 8.22.0 postcss-preset-mantine: specifier: ^1.18.0 version: 1.18.0 posthog-js: - specifier: ^1.255.0 - version: 1.386.6 + specifier: ^1.391.2 + version: 1.391.2 posthog-node: - specifier: ^4.17.0 + specifier: ^4.18.0 version: 4.18.0 prismjs: specifier: ^1.30.0 @@ -499,11 +499,11 @@ catalogs: specifier: ^5.3.1 version: 5.3.1 testcontainers: - specifier: ^12.0.2 - version: 12.0.2 + specifier: ^12.0.3 + version: 12.0.3 timezones-ical-library: - specifier: ^2.2.0 - version: 2.2.0 + specifier: ^2.2.1 + version: 2.2.1 trpc-to-mcp: specifier: ^1.3.2 version: 1.3.2 @@ -529,8 +529,8 @@ catalogs: specifier: ^1.8.1 version: 1.8.1 video.js: - specifier: ^8.23.7 - version: 8.23.7 + specifier: ^8.23.9 + version: 8.23.9 vite: specifier: ^8.0.16 version: 8.0.16 @@ -538,8 +538,8 @@ catalogs: specifier: ^6.1.1 version: 6.1.1 vitest: - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^4.1.9 + version: 4.1.9 winston: specifier: 3.19.0 version: 3.19.0 @@ -565,18 +565,18 @@ catalogs: overrides: '@babel/helpers@<7.26.10': '>=7.29.7' '@babel/runtime@<7.26.10': '>=7.29.7' - axios@>=1.0.0 <1.8.2: '>=1.17.0' + axios@>=1.0.0 <1.8.2: '>=1.18.0' brace-expansion@>=2.0.0 <=2.0.1: '>=5.0.6' brace-expansion@>=1.0.0 <=1.1.11: '>=5.0.6' esbuild@<=0.24.2: '>=0.28.0' form-data@>=4.0.0 <4.0.4: '>=4.0.6' - hono@<4.6.5: '>=4.12.25' + hono@<4.6.5: '>=4.12.26' linkifyjs@<4.3.2: '>=4.3.3' - nanoid@>=4.0.0 <5.0.9: '>=5.1.11' + nanoid@>=4.0.0 <5.0.9: '>=5.1.15' prismjs@<1.30.0: '>=1.30.0' proxmox-api>undici: 7.27.1 react-is: ^19.2.7 - rollup@>=4.0.0 <4.22.4: '>=4.62.0' + rollup@>=4.0.0 <4.22.4: '>=4.62.2' sha.js@<=2.4.11: '>=2.4.12' tar-fs@>=3.0.0 <3.0.9: '>=3.1.2' tar-fs@>=2.0.0 <2.1.3: '>=3.1.2' @@ -597,7 +597,7 @@ importers: devDependencies: '@playwright/test': specifier: 'catalog:' - version: 1.60.0 + version: 1.61.0 '@semantic-release/changelog': specifier: 'catalog:' version: 6.0.3(semantic-release@25.0.5(typescript@6.0.3)) @@ -618,7 +618,7 @@ importers: version: 14.1.1(semantic-release@25.0.5(typescript@6.0.3)) '@testcontainers/redis': specifier: 'catalog:' - version: 12.0.2 + version: 12.0.3 '@turbo/gen': specifier: 'catalog:' version: 2.9.18(@types/node@24.13.2) @@ -627,10 +627,10 @@ importers: version: 6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.9(vitest@4.1.9) '@vitest/ui': specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) + version: 4.1.9(vitest@4.1.9) conventional-changelog-conventionalcommits: specifier: 'catalog:' version: 9.3.1 @@ -645,16 +645,16 @@ importers: version: 2.2.3 oxfmt: specifier: 'catalog:' - version: 0.54.0 + version: 0.55.0 oxlint: specifier: 'catalog:' - version: 1.69.0 + version: 1.70.0 semantic-release: specifier: 'catalog:' version: 25.0.5(typescript@6.0.3) testcontainers: specifier: 'catalog:' - version: 12.0.2 + version: 12.0.3 turbo: specifier: 'catalog:' version: 2.9.18 @@ -669,7 +669,7 @@ importers: version: 6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) vitest: specifier: 'catalog:' - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + version: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) apps/docs: dependencies: @@ -705,7 +705,7 @@ importers: version: 0.99.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@scalar/api-reference-react': specifier: 'catalog:' - version: 0.9.46(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) + version: 0.9.47(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) '@signalwire/docusaurus-plugin-llms-txt': specifier: ^1.2.2 version: 1.2.2(@docusaurus/core@3.10.1(@docusaurus/faster@3.10.1(@docusaurus/types@3.10.1(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@swc/helpers@0.5.15)(esbuild@0.28.0)(postcss@8.5.15))(@mdx-js/react@3.1.1(@types/react@19.2.17)(react@19.2.7))(@rspack/core@1.7.11(@swc/helpers@0.5.15))(@swc/core@1.15.3(@swc/helpers@0.5.15))(esbuild@0.28.0)(postcss@8.5.15)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)) @@ -799,7 +799,7 @@ importers: version: 3.2.2(react@19.2.7) '@gfazioli/mantine-onboarding-tour': specifier: 'catalog:' - version: 4.0.4(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 4.0.5(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@homarr/analytics': specifier: workspace:^0.1.0 version: link:../../packages/analytics @@ -895,28 +895,28 @@ importers: version: link:../../packages/widgets '@mantine/colors-generator': specifier: 'catalog:' - version: 9.3.1(chroma-js@3.2.0) + version: 9.3.2(chroma-js@3.2.0) '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/dropzone': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) '@mantine/modals': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/tiptap': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tiptap/extension-link@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))(@tiptap/react@3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tiptap/extension-link@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))(@tiptap/react@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@modelcontextprotocol/sdk': specifier: 'catalog:' version: 1.29.0(zod@4.4.3) '@scalar/api-reference-react': specifier: 'catalog:' - version: 0.9.46(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) + version: 0.9.47(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) @@ -931,13 +931,13 @@ importers: version: 5.101.0(@tanstack/react-query@5.101.0(react@19.2.7))(react@19.2.7) '@tanstack/react-query-next-experimental': specifier: 'catalog:' - version: 5.101.0(@tanstack/react-query@5.101.0(react@19.2.7))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7) + version: 5.101.0(@tanstack/react-query@5.101.0(react@19.2.7))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7) '@trpc/client': specifier: 'catalog:' version: 11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3) '@trpc/next': specifier: 'catalog:' - version: 11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/react-query@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(react@19.2.7)(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3) + version: 11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/react-query@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(react@19.2.7)(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3) '@trpc/react-query': specifier: 'catalog:' version: 11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(react@19.2.7)(typescript@6.0.3) @@ -976,7 +976,7 @@ importers: version: 17.4.2 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) flag-icons: specifier: 'catalog:' version: 7.5.0 @@ -985,7 +985,7 @@ importers: version: 13.0.6 isomorphic-dompurify: specifier: 'catalog:' - version: 3.17.0(@noble/hashes@2.0.1) + version: 3.18.0(@noble/hashes@2.0.1) jotai: specifier: 'catalog:' version: 2.20.1(@babel/core@7.29.0)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7) @@ -994,25 +994,25 @@ importers: version: 3.10.1 lucide-react: specifier: 'catalog:' - version: 1.18.0(react@19.2.7) + version: 1.21.0(react@19.2.7) mantine-datatable: specifier: 'catalog:' - version: 9.3.0(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) mantine-react-table: specifier: 'catalog:' - version: mantine-react-table-open@9.0.3(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: mantine-react-table-open@9.0.3(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) mcp-handler: specifier: 'catalog:' - version: 1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) + version: 1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) postcss-preset-mantine: specifier: 'catalog:' version: 1.18.0(postcss@8.5.15) posthog-js: specifier: 'catalog:' - version: 1.386.6 + version: 1.391.2 prismjs: specifier: 'catalog:' version: 1.30.0 @@ -1039,7 +1039,7 @@ importers: version: 2.2.6 trpc-to-mcp: specifier: 'catalog:' - version: 1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3) + version: 1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3) use-deep-compare-effect: specifier: 'catalog:' version: 1.8.1(react@19.2.7) @@ -1334,7 +1334,7 @@ importers: version: 4.5.0 next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -1346,7 +1346,7 @@ importers: version: 2.2.6 trpc-to-mcp: specifier: 'catalog:' - version: 1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3) + version: 1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3) trpc-to-openapi: specifier: 'catalog:' version: 3.3.0(patch_hash=2ca3c16af0fcca0c736697ad4fe553a14f794524fa9ce0d5c3e8ee4aea76090c)(@trpc/server@11.17.0(typescript@6.0.3))(zod-openapi@5.3.0(zod@4.4.3))(zod@4.4.3) @@ -1395,10 +1395,10 @@ importers: version: 8.1.8 next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) next-auth: specifier: 'catalog:' - version: 5.0.0-beta.31(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7) + version: 5.0.0-beta.31(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7) react: specifier: 'catalog:' version: 19.2.7 @@ -1488,7 +1488,7 @@ importers: version: 1.11.21 next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) octokit: specifier: 'catalog:' version: 5.0.5 @@ -1528,7 +1528,7 @@ importers: version: 0.2.9 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) ioredis: specifier: 'catalog:' version: 5.11.1 @@ -1537,7 +1537,7 @@ importers: version: 3.22.5(@types/node@24.13.2) pg: specifier: 'catalog:' - version: 8.21.0 + version: 8.22.0 superjson: specifier: 'catalog:' version: 2.2.6 @@ -1682,16 +1682,16 @@ importers: version: link:../validation '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@paralleldrive/cuid2': specifier: 'catalog:' version: 3.3.0 '@testcontainers/mysql': specifier: 'catalog:' - version: 12.0.2 + version: 12.0.3 '@testcontainers/postgresql': specifier: 'catalog:' - version: 12.0.2 + version: 12.0.3 better-sqlite3: specifier: 'catalog:' version: 12.10.0 @@ -1703,16 +1703,16 @@ importers: version: 0.31.10 drizzle-orm: specifier: 'catalog:' - version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + version: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) drizzle-zod: specifier: 'catalog:' - version: 0.8.3(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(zod@4.4.3) + version: 0.8.3(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(zod@4.4.3) mysql2: specifier: 'catalog:' version: 3.22.5(@types/node@24.13.2) pg: specifier: 'catalog:' - version: 8.21.0 + version: 8.22.0 superjson: specifier: 'catalog:' version: 2.2.6 @@ -1746,7 +1746,7 @@ importers: version: link:../common fast-xml-parser: specifier: 'catalog:' - version: 5.8.0 + version: 5.9.3 zod: specifier: 'catalog:' version: 4.4.3 @@ -1796,7 +1796,7 @@ importers: version: link:../validation '@mantine/form': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) zod: specifier: 'catalog:' version: 4.4.3 @@ -1836,7 +1836,7 @@ importers: version: link:../validation '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: specifier: 'catalog:' version: 19.2.7 @@ -1902,7 +1902,7 @@ importers: version: 8.0.0 '@ctrl/qbittorrent': specifier: 'catalog:' - version: 9.12.2 + version: 9.14.0 '@ctrl/transmission': specifier: 'catalog:' version: 7.4.0 @@ -1959,7 +1959,7 @@ importers: version: 1.1.1 timezones-ical-library: specifier: 'catalog:' - version: 2.2.0 + version: 2.2.1 tsdav: specifier: 'catalog:' version: 2.2.2 @@ -2002,10 +2002,10 @@ importers: version: link:../ui '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) react: specifier: 'catalog:' version: 19.2.7 @@ -2054,7 +2054,7 @@ importers: version: link:../validation '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) @@ -2063,7 +2063,7 @@ importers: version: 1.11.21 next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2088,7 +2088,7 @@ importers: version: link:../ui '@mantine/notifications': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) @@ -2137,16 +2137,16 @@ importers: version: link:../validation '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) adm-zip: specifier: 'catalog:' version: 0.5.17 next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2308,10 +2308,10 @@ importers: version: link:../server-settings '@mantine/dates': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2363,13 +2363,13 @@ importers: version: link:../ui '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) '@mantine/spotlight': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) @@ -2378,7 +2378,7 @@ importers: version: 2.20.1(@babel/core@7.29.0)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2412,13 +2412,13 @@ importers: version: 4.3.1 mantine-react-table: specifier: 'catalog:' - version: mantine-react-table-open@9.0.3(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: mantine-react-table-open@9.0.3(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) next-intl: specifier: 'catalog:' - version: 4.13.0(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)(typescript@6.0.3) + version: 4.13.0(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)(typescript@6.0.3) react: specifier: 'catalog:' version: 19.2.7 @@ -2452,13 +2452,13 @@ importers: version: link:../validation '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/dates': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) @@ -2467,10 +2467,10 @@ importers: version: 4.2.0 mantine-react-table: specifier: 'catalog:' - version: mantine-react-table-open@9.0.3(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: mantine-react-table-open@9.0.3(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2589,67 +2589,67 @@ importers: version: link:../validation '@mantine/charts': specifier: 'catalog:' - version: 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)) + version: 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)) '@mantine/core': specifier: 'catalog:' - version: 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@mantine/form': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) '@mantine/hooks': specifier: 'catalog:' - version: 9.3.1(react@19.2.7) + version: 9.3.2(react@19.2.7) '@tabler/icons-react': specifier: 'catalog:' version: 3.44.0(react@19.2.7) '@tiptap/extension-color': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-text-style@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))) + version: 3.27.1(@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))) '@tiptap/extension-highlight': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) '@tiptap/extension-image': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) '@tiptap/extension-link': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) '@tiptap/extension-placeholder': specifier: 'catalog:' - version: 3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-table': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) '@tiptap/extension-table-cell': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-table-header': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-table-row': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-task-item': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-task-list': specifier: 'catalog:' - version: 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) '@tiptap/extension-text-align': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) '@tiptap/extension-text-style': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) '@tiptap/extension-underline': specifier: 'catalog:' - version: 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + version: 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) '@tiptap/react': specifier: 'catalog:' - version: 3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tiptap/starter-kit': specifier: 'catalog:' - version: 3.26.1 + version: 3.27.1 clsx: specifier: 'catalog:' version: 2.1.1 @@ -2661,16 +2661,16 @@ importers: version: 10.4.0 lucide-react: specifier: 'catalog:' - version: 1.18.0(react@19.2.7) + version: 1.21.0(react@19.2.7) mantine-datatable: specifier: 'catalog:' - version: 9.3.0(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 9.3.1(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) mantine-react-table: specifier: 'catalog:' - version: mantine-react-table-open@9.0.3(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: mantine-react-table-open@9.0.3(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next: specifier: 'catalog:' - version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: specifier: 'catalog:' version: 19.2.7 @@ -2691,7 +2691,7 @@ importers: version: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) video.js: specifier: 'catalog:' - version: 8.23.7 + version: 8.23.9 zod: specifier: 'catalog:' version: 4.4.3 @@ -3958,8 +3958,8 @@ packages: resolution: {integrity: sha512-fEfw3AeQ8XhVsNzogZrnyTNDD/Tpbfl3ybHsspBMvj0UKctabApv1JV3JJUQG/hoX6hiO+DtQS+acN7dMPX01g==} engines: {node: '>20'} - '@ctrl/qbittorrent@9.12.2': - resolution: {integrity: sha512-eU/SLUYmD4vixvwdLe/u+Ks2ucd8n9ZouKLFyVX9VOMz4Q6syvccwoS2/WobDyTCWLuhEBXIqF2N4NOUUi0LBA==} + '@ctrl/qbittorrent@9.14.0': + resolution: {integrity: sha512-Ye1yX6zahOugx6RHQoiBkE8Od21RmO3i1gbSrOSYtoDIqr+9Utz8Rf6FkY7IEKB8JbeWjwuEhQt23usmhcFt5Q==} engines: {node: '>=18'} '@ctrl/shared-torrent@6.5.1': @@ -4819,8 +4819,8 @@ packages: '@formatjs/intl-localematcher@0.8.1': resolution: {integrity: sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA==} - '@gfazioli/mantine-onboarding-tour@4.0.4': - resolution: {integrity: sha512-8O70elJVFSJJCB/Ie4TDxAKuDgE1BRU8o7O7ArFWzPYGx4Sa4jWW8OC0QyjxZul5aFaFJFl55lG263oh7IMkHg==} + '@gfazioli/mantine-onboarding-tour@4.0.5': + resolution: {integrity: sha512-KyzmbcUqnUuezGZKIpsb6zeTlLgjetBQksysfYhuP8wfuqObkAL+aD0DnHnaxrdHxR9GYFkiIDImhHDUG1p5Vw==} peerDependencies: '@mantine/core': '>=9.0.0' '@mantine/hooks': '>=9.0.0' @@ -4881,7 +4881,7 @@ packages: resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} engines: {node: '>=18.14.1'} peerDependencies: - hono: '>=4.12.25' + hono: '>=4.12.26' '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -5223,6 +5223,10 @@ packages: '@ioredis/commands@1.10.0': resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@isaacs/cliui@9.0.0': resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} engines: {node: '>=18'} @@ -5438,88 +5442,88 @@ packages: '@libsql/core@0.14.0': resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} - '@mantine/charts@9.3.1': - resolution: {integrity: sha512-T09AnLs+yhjw97kqC2RHC58yj7YzaGRDRbANOONt7DPsRcSxHq8snQ9Qo4GrzxjcLUgXlN2eR1UfM4QHlY6y9A==} + '@mantine/charts@9.3.2': + resolution: {integrity: sha512-G3cFLLxmmRr0ij5fOHeO/jqR/U+DnMNZy0S7GEvs4lIzDRl871TDb1BogZyeHUGKuLnsLBYpTA719IcmswYGMw==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 recharts: '>=3.2.1' - '@mantine/colors-generator@9.3.1': - resolution: {integrity: sha512-BkY9JSAZq5J9yw/58WWqRHlt8pFJpu2MhN1bzILVTdu3sLVpYhJP0LnCvFb5InqYZQ6VLSui06B/Px4pObYRuw==} + '@mantine/colors-generator@9.3.2': + resolution: {integrity: sha512-q2sqR2vCwdkDD/OuTcmfvkg66Wc6avepYB+073qh75YP3+EPa60Ng/h3Vfgmt+G2iTsqURJgCAbCLaZZr/9g4Q==} peerDependencies: chroma-js: '>=2.4.2' - '@mantine/core@9.3.1': - resolution: {integrity: sha512-4rBoHpggSohayE+Os7lKdbsHTw7m/uZRKYjk9DN6cKBhQIjdiULdcG+b4b5CMVZSqZDHPgT70uWGI7yqkn8Ufw==} + '@mantine/core@9.3.2': + resolution: {integrity: sha512-Upy/Z9Sj2eW2dGrFgUy/2kISVsxMTBYTDfP2TFdsIA3PdPSBkdqfSOPX/ug3d3F3a4bnwQSqcO6+aPEpBIh8dg==} peerDependencies: - '@mantine/hooks': 9.3.1 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/dates@9.3.1': - resolution: {integrity: sha512-Nh4XQyyV1AM0XRnUJugb1kNfCm++nkticsO8aroKmFPZ7cpGV7cjdL+4MJNPu1atS1EUePXl2VLLpKnrclpqOQ==} + '@mantine/dates@9.3.2': + resolution: {integrity: sha512-MzHrXGoOb3rCnHBlsI/BPAjC8K5tZ4f8pzg66tsTsupVCQBaBpHSVatQwNRJ6K2JC9pyCyTa9BL803C8AiWycA==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 dayjs: '>=1.0.0' react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/dropzone@9.3.1': - resolution: {integrity: sha512-WsjsMH9NUz5y9XAR/vOUbyb+y0X0Kud6KV1K/xURwrbxena2b1tl+WvjPO/6vRiJeTpFlMuoWF/8nwqnxoGUeg==} + '@mantine/dropzone@9.3.2': + resolution: {integrity: sha512-wx/6wSVLVW+OfPU9FgkMkfnaUd7roPZG1zOlzE6EIRYIqsHciY3OAlrhQDpYnTkowsseJpXDg4JG788l5kNDUQ==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/form@9.3.1': - resolution: {integrity: sha512-dGJPcYGkfDnAPKHcnzgf2mSlnjwymaOyROiTEJNbbjE3OVoWbPaw8HwEKav1wATdxNYR9Bw1GHtbfbGTsm1Jww==} + '@mantine/form@9.3.2': + resolution: {integrity: sha512-jWEXcx8hhddOsny+q/lFtVToNS3VBJYICrkfFMWJsN+WAZamnPItWTPLqulTYVp1T8uma9MsEZ1LX4kqWUFANA==} peerDependencies: react: ^19.2.0 - '@mantine/hooks@9.3.1': - resolution: {integrity: sha512-zAOlxV59j5CDgAnExN+ypaR6dVW1vwMKDvKUxIlUVd/e52qxYnPyYRD+shJmyOLaZRuQmVF0R/7mJAjt2jw9cA==} + '@mantine/hooks@9.3.2': + resolution: {integrity: sha512-jOjpUe0x1A/k3XUiu2/aaSCasXRI5ZKZOucm3ypwsvm9F2u8C1xzwBvagrzlbNZwJRF5vNYIJtCaT7NunPyc0A==} peerDependencies: react: ^19.2.0 - '@mantine/modals@9.3.1': - resolution: {integrity: sha512-JqP1o6hrfQJ5UCq97HJsI7uIPDy+WwvWwkkfctWqcYkFJA2DU8dVoPqvEhnhDQUIXNci3sx6XDoQZAq1Qg57mw==} + '@mantine/modals@9.3.2': + resolution: {integrity: sha512-XorW2PcYU+DQQVZmY80OlwI/bgkBPzf9MscjEZep8Z3aowrlNpnJXFbu2RoPCPMwROU2nX4gt0HJP2OiuGr28A==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/notifications@9.3.1': - resolution: {integrity: sha512-irkD9uszgVftthbCLd+4lS7M1jkhL4sVrZASv8+43aIkncW+oQkCFpBuaOAf6uRcMjmQ7XnKs2O8bXYzl/DqgQ==} + '@mantine/notifications@9.3.2': + resolution: {integrity: sha512-mnda8hE/DizPi5Bbiwd2M2jXxfSZSUeayvnLYMbFweGQKXM+QRmX1ootyDRVqWew8paltewTNp84cWLjj/6fKw==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/spotlight@9.3.1': - resolution: {integrity: sha512-NsNXywYhKuHnESoMCX1+e2za0GQJYQ43zMUIkr8XwHiyIzdU/tmFJh+k+jfUeFKPfnS5uRy+vJvC6z320aNbTw==} + '@mantine/spotlight@9.3.2': + resolution: {integrity: sha512-JAJhW51qvYNiPTEnX9ewZX521gKDsVsmaecuuR2iNyk0NbrOPB5SWF9ZZrPSMwFVtqnqYHziq5BLukzlf+kG/Q==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 react: ^19.2.0 react-dom: ^19.2.0 - '@mantine/store@9.3.1': - resolution: {integrity: sha512-UZ8wGKfF/NFMHCDl1Rd0M8XtHdt4W1w3V4ohNpFSaP3nSjJ+Cu1FT+iIWtXwC0Ogha8XnuVQ7vm/dw2BUfpw+g==} + '@mantine/store@9.3.2': + resolution: {integrity: sha512-uNmvjkwfUHZJ5bvzQroLFvubuUAHjBM0rh69RBRsUCG5FR5K4f8y4SX8+lch0wS6UJuuvodsSIK8H5jvZuFSgQ==} peerDependencies: react: ^19.2.0 - '@mantine/tiptap@9.3.1': - resolution: {integrity: sha512-trXZ6mN6p3ukxudOuC8r+PapA7UVQ/az4cSOmiE3m8n1s3IcoyaiwAB5l2iM/Df9lByhs1B6ka8SG1F6Wda2NQ==} + '@mantine/tiptap@9.3.2': + resolution: {integrity: sha512-X344wqt3eusMLPANWuNSnKoFjTDlCEOUpYq6hPWU6uBvxEHJGHuJFXjtm/jg/D6aNEvWr+P+m1+ElE7eLT/G0A==} peerDependencies: - '@mantine/core': 9.3.1 - '@mantine/hooks': 9.3.1 + '@mantine/core': 9.3.2 + '@mantine/hooks': 9.3.2 '@tiptap/extension-link': '>=3.3.0' '@tiptap/react': '>=3.3.0' react: ^19.2.0 @@ -5711,8 +5715,8 @@ packages: resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} - '@nodable/entities@2.1.0': - resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} + '@nodable/entities@2.2.0': + resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -5859,246 +5863,246 @@ packages: '@oxc-project/types@0.133.0': resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - '@oxfmt/binding-android-arm-eabi@0.54.0': - resolution: {integrity: sha512-NAtpl/SiaeU103e7/OmZw0MvUnsUUopW7hEm/ecegJg7YM0skQaA0IXEZoyTV6NUdiNPupdIUreRqUZTShbn/g==} + '@oxfmt/binding-android-arm-eabi@0.55.0': + resolution: {integrity: sha512-+rFDOqQe5LOWgxrAJaZgLRudr6GQm0wGI6gtu7vVkrdLGjNMUSGbAlaCr8j7F2H2Er97vYQCU8WDb30onqMM1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.54.0': - resolution: {integrity: sha512-B4VZfBUlKK1rmMChsssNZbkZjE8+FzG3avMjGgMDwbGxXRoXkoeXiAZ+78Oa+eyDPHvDCiUb4zH/vmCOUSafLQ==} + '@oxfmt/binding-android-arm64@0.55.0': + resolution: {integrity: sha512-ctulLq8s3x8Zmvw6+iccB09TIKERAklRSmbJ10gk8mlAn05qZxoyo52dj3Hi9IJcmDSwF54fQaTVh2CbL6PInw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.54.0': - resolution: {integrity: sha512-i02vF75b+ePsQP3tHqSxVYI5S6b8X/xqdPu7/mDHXtpgXLTYXi3jJmfHU0j+dnZZDKaYTx/ioCK7QYJmtiJR2g==} + '@oxfmt/binding-darwin-arm64@0.55.0': + resolution: {integrity: sha512-xDQczLH9pw/RBk1h/GH0qcGMm8hQtmtVHBNLSH3lk1gEIR09hZ4L+mJQl4VqiVAvPK9VG9PYrWWuSQLt7xTbiA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.54.0': - resolution: {integrity: sha512-8VMFvGvooXj7mswkbrhdVZ2/sgiDaBzWpkkbtO+qGDLV4EfJd67nQadHkQC0ZNbaWA9ajXfqI6i7PZLIeDzxEQ==} + '@oxfmt/binding-darwin-x64@0.55.0': + resolution: {integrity: sha512-JaNoFCkF2CJdGgpPSMbuO9HVyXyoNGIhMHPvp6NYAjeVKw9XEYc0HcUWJLPQa3Q69WV5wMa9m5jPMJPtbLtcRg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.54.0': - resolution: {integrity: sha512-0cRHnp43WN1Jrc5s0BdbdKgR1XirdvHy7TAFi3JEsoEVQVJxTXMbpVd76sxXlgRswNMDhVFSJw+y7Eb8mEavFQ==} + '@oxfmt/binding-freebsd-x64@0.55.0': + resolution: {integrity: sha512-DNbszhpg6S2MIzax5azdHFTTBIVkR5xr8yyRZuA4yoDAwOkzIp3tmldgKZM2+VlT+hJIG0xUksA+elISzMEAfA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': - resolution: {integrity: sha512-JyQAk3hK/OEtup7Rw6kZwfdzbKqTVD5jXXb8Xpfay29suwZyfBDMVW/bj4RqEPySYWc6zCp198pOluf8n5uYzg==} + '@oxfmt/binding-linux-arm-gnueabihf@0.55.0': + resolution: {integrity: sha512-2snoaoRfFFyGnbOcKUK36rREBYxe/Xgz3uHbiA5zbCB/s6R4DQj4mHqYAaWWhgizCUSDxV8cE9zAZ0XleNpKGw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.54.0': - resolution: {integrity: sha512-qnvLatTpM8vtvjOfcckBOzJjk+n6ce/wwpP8OFeUrD5aNLYcKyWAitwj+Rk3PK9jGanbZvKsJnv14JGQ6XqFdw==} + '@oxfmt/binding-linux-arm-musleabihf@0.55.0': + resolution: {integrity: sha512-q1aktHF/WRpSK81BX1dE/9vWrS2jGw1Nax2kb4DBLGAewubCLcoNyp4Zl/NSMgbv3vUS46Z33wIQkBVYOP3PYg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.54.0': - resolution: {integrity: sha512-SMkhnCzIYZYDk9vw3W/80eeYKmrMpGF0Giuxt4HruFlCH7jEtnPeb3SdQKMfgYi/dgtaf+hZAb5XWPYnxqCQ3w==} + '@oxfmt/binding-linux-arm64-gnu@0.55.0': + resolution: {integrity: sha512-VD0y36aENezl/3tsclA/4G53Cc7iV+7Uoh7gz4yvcOTaEYBtJpQsE6PKDGTtUtOvGS4kv51ybfXY/nWZejO5IA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.54.0': - resolution: {integrity: sha512-QrwJlBFFKnxOd95TAaszpMbZBLzMoYMpGaQTZF8oibacnF5rv8l12IhILhQRPmksWiBqg0YSe2Mnl7ayeJAHSA==} + '@oxfmt/binding-linux-arm64-musl@0.55.0': + resolution: {integrity: sha512-r8xlKJFcsRmn0H5jZrdORae6RX9jDBrZVvOoxF+bCQtampQJClv80aZEHsv+NsLsp2KCE5ql79O7DpPVzYWpXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.54.0': - resolution: {integrity: sha512-WILatiol/TUHTlhod7R09+7Az/XlhKwmY1MHfLZNmewltPWNN/EwxP2rQSHahibZ/cB8gmckEBjBOByD+5bYsQ==} + '@oxfmt/binding-linux-ppc64-gnu@0.55.0': + resolution: {integrity: sha512-GRKv/HXHcwIVld/WU61rF0g0R16hl5EJ+ScKdpjevT57lnLnagj/U2YUbXf2mT+2Pg1uCzWC+mvGicPV3CDdLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.54.0': - resolution: {integrity: sha512-f05YMG4BH4G8S4ME6UM6fi1MnJ9094mrnvO5Pa4SJlMfWlUM+1/ZWMEF4NnjM7shZAvbHsHRuVYpUo0PHC4P9Q==} + '@oxfmt/binding-linux-riscv64-gnu@0.55.0': + resolution: {integrity: sha512-rdv57enTiPtpSYRMKfAiEbQb0Puw5t9N7isVinDoo5qeLDScro2gznmZqSgSWbVZRzLisTeCTW8Qwgw0bOHv3A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.54.0': - resolution: {integrity: sha512-UfL+2hj1ClNqcCRT9s8vBU4axDpjxgVxX96G+9DYAYjoc5b0u15CJtn2jgsi9iM+EbGNc5CW1HVRgwVu76UsSA==} + '@oxfmt/binding-linux-riscv64-musl@0.55.0': + resolution: {integrity: sha512-7v1nNrlD43VY6+sYQ6efYyb3lE6QY182304PD/768ZxTjOmFd/3dQa3u/nGBUAXYdGSWOQc5N3PnS0QzUXyEIA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.54.0': - resolution: {integrity: sha512-3/XZe931Hka+J6NjnaqJzYpsWWxDTuRdUdwSQHnOuJEgbC+SehIMFJS8hsEjV7LBhVSL2OCnRLvbVW8O97XIyw==} + '@oxfmt/binding-linux-s390x-gnu@0.55.0': + resolution: {integrity: sha512-f4lJLUSPOgScjFl9LiflKCTocyNRwE25JmTMbN4XQdDjoZzEHjqf3wA3VESF1/csg7i8m7+EQLbrZyYDqe10UQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.54.0': - resolution: {integrity: sha512-Ik93RlObtu43GbxApafayFjwYE06L6Xr08cSwpBPYbDrLp2ReZx0Jm1DqwRyYRnukUJy+rK2WaEvUQOxdytU9Q==} + '@oxfmt/binding-linux-x64-gnu@0.55.0': + resolution: {integrity: sha512-MihqiPziJNoWy4MqNSV+jVA1g+07iQDjZiR0vaCaDoPgFEiJpCMsxamktzLV07cEeQsSJ04vQaU4CzCQwIvtDA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.54.0': - resolution: {integrity: sha512-yZcakmPlD86CNymknd7KfW+FH+qfbqJH+i0h69CYfV1+KMoVeM9UED+8+TDVoU4haxI0NxY7RPCvRLy3Sqd2Qg==} + '@oxfmt/binding-linux-x64-musl@0.55.0': + resolution: {integrity: sha512-Yqghym7KYAVjP9MmSrNZiDeerMuoejNjo0r3ox5H3GDKk8eAfl8VyJm9i+pWCLDCTnAbcTUMMN2ZKjUYXH1v3g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.54.0': - resolution: {integrity: sha512-GiVBZNnEZnKu00f1jTg49nomv187d0GQX+O+ocykoLeiaALuEO+swoTehHn9TehTfi7V8H0i0e/yvUjCqnwk1w==} + '@oxfmt/binding-openharmony-arm64@0.55.0': + resolution: {integrity: sha512-s5SDvVVSbyQl1V5UU3Yl12M+XLUQ3rl5SglNqgAA2K4PXUtQhyNSS00wivONPEnNo5W01rCou8WkDNyvI/RGHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.54.0': - resolution: {integrity: sha512-J0SSB8Z1Fre2sxRolYcW6Rl1RQmKdQ2hnHyq4YJrfBRiXTObLw4DXnIVraM/UyqGqwOi7yTrQA4VT7DPxlHVKA==} + '@oxfmt/binding-win32-arm64-msvc@0.55.0': + resolution: {integrity: sha512-7p9FB5R32tw2KyyNX3wpQrR2WHwEHvMEiBlGXxeTCaRMCVNx3UtFMAUbaQ/pRNWIrEUZmYhJ6tcUH52uPTRYjQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.54.0': - resolution: {integrity: sha512-O61UDVj8zz6yXJjkHPf05VaMLOXmEF8P5kf/N0W7AQMmd6bcQogl+KJc7rMutKTL524oE9iH32JXZClBFmEQIg==} + '@oxfmt/binding-win32-ia32-msvc@0.55.0': + resolution: {integrity: sha512-ZYqj3fDnOT1IaVGMP5kpmkQl4F3tQIm2ZyAxvqkJYmI0xgWWak4ss4XYwv3VDfM+TWXeC9K4uQ/wW5jm/5XABA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.54.0': - resolution: {integrity: sha512-1MDpqJPiFqxWtIHas8vkb1VZ7f7eKyTffAwmO8isxQYMaG1OFKsH666BWLeXQLO+IWNfiMssLD55hbR1lIPTqg==} + '@oxfmt/binding-win32-x64-msvc@0.55.0': + resolution: {integrity: sha512-eEYT5tivGnGbPHuOHuQpi6CGLObhh0re/5jcNQHihD2GRYkTM85dyi5a19zjP8Q00t1uqAx+/QGLUGdHeqzWyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.69.0': - resolution: {integrity: sha512-DKQQbD5cZ/MYfDgDI7YGyGD9FSxABlsBsYFo5p26lloob543tP9+4N3guwdXIYJN+7HSZxLe8YJuwcOWw5qnHg==} + '@oxlint/binding-android-arm-eabi@1.70.0': + resolution: {integrity: sha512-zFh0P4cswmRvw6nkyb89dr18rRanuaCPAsEXsFDoQY8WdaquI8Pt4NWFjaMJg6L23cy5NeN8J9cBnREbWzZhaw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.69.0': - resolution: {integrity: sha512-lEhb+I5pr4inux+JFwfCa1HRq3Os7NirEFQ0H1I35SVEHPm6byX0Ah47xmRha3qi6LAkxUcxViL8o/9PivjzBg==} + '@oxlint/binding-android-arm64@1.70.0': + resolution: {integrity: sha512-qI8o4HZjeGiBrWv+pJv4lH0Yi2Gl/JSp/EumBUApezJprIKa5PS4nU0lQsQngtky8k+SplQIOjv6hwu0SSxeyg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.69.0': - resolution: {integrity: sha512-GY2YE8lOZW59BW1Ia1y+1gR0XyjrZRvVWHAr8LGeGhYHE0OQJ/7cRKXTkx1P+E9/6awEc3SX8a68SFTjh/E//A==} + '@oxlint/binding-darwin-arm64@1.70.0': + resolution: {integrity: sha512-8KjgVVHI5F9nVwHCRwwA78Ty7zNKP4Wd9OeN5PSv3iu/F/u1RVXoOCgLhWqust6HmwQG6xc8c+RCyaWENy24+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.69.0': - resolution: {integrity: sha512-ax1oZnOjHX3LB7myQyHEaQkDwfLb6str3/nSP6O7EVUviQGNkEGzGV0EqcBJWK+Ufwx0l4xPgyYayurvhAdl2Q==} + '@oxlint/binding-darwin-x64@1.70.0': + resolution: {integrity: sha512-WVydssv5PSUBXFJTdNBWlmGkbNmvPGaFt/2SUT/EZRB6bq6bEOHmMlbnupZD5jmlEvi9+mZJHi8TCw15lyfSfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.69.0': - resolution: {integrity: sha512-kHWeHv4g2h8NY+mpCxzCtY4uerMJWTN/TSnNj1CPbakFpHEJ6cTya2wWV0pDSYWOJ2+0UiEbhn3AtXxHtsnKjg==} + '@oxlint/binding-freebsd-x64@1.70.0': + resolution: {integrity: sha512-hJucmUf8OlinHNb1R7fI4Fw6WsAstOz7i8nmkWQfiHoZXtbufNm+MxiDTIMk1ggh2Ro4vLzgQ+bKvRY54MZoRA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': - resolution: {integrity: sha512-gq84vM1a1oEehXo27YCDzGVcxPsZDI1yswZwz2Da1/cbnWtrL16XZZnz0G/+gIU8edtHpfjxq5c+vWEHqJfWoQ==} + '@oxlint/binding-linux-arm-gnueabihf@1.70.0': + resolution: {integrity: sha512-1BnS7wbCYDSXwWzJJ+mc3NURoha6m6m6RT5c6vgAY3oz7C3OVXP+S0awo2mRq97arrJkVvO3qRQfyAHL+76xtQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.69.0': - resolution: {integrity: sha512-kIqEa98JQ0VRyrcncxA417m2AzasqTlD+FyVT1AksjvjkqQcvm7pBWYvoW3/mpyOP2XYvi5nSCCTIe6De1yu5g==} + '@oxlint/binding-linux-arm-musleabihf@1.70.0': + resolution: {integrity: sha512-yKy/UdbR55+M2yEcuiV5DCNC/gdQAjr/GioUy50QwBzSrKm8ueWADqyRLS9Xk+qjNeCYGg6A8FvUBds56ttfqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.69.0': - resolution: {integrity: sha512-j+xYiXozxGWx2cpjCrwwGR4awTxPFsRv3JZrv23RCogEPMc4R7UqjHW47p/RG0aRlbWiROCJ8coUfCwy0dvzHA==} + '@oxlint/binding-linux-arm64-gnu@1.70.0': + resolution: {integrity: sha512-0A5XJ4alvmqFUFP/4oYSyaO+qLto/HrKEWTSaegiVl+HOufFngK2BjYw9x4RbwBt/du5QG6l5q1zeWiJYYG5yg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.69.0': - resolution: {integrity: sha512-xEPpNppTfN1l/nM7gYSf9iocscu/as+p/7vxkLeLEKnYU+09Dm+5V6IhDYDh+Uz6FajEupWwCLt5SOG0y1PCKg==} + '@oxlint/binding-linux-arm64-musl@1.70.0': + resolution: {integrity: sha512-JiylyurlB0CLSedNtx1gzv3FvfWPF1h/2Y3BJszPLNt5XQFlBsH5ke0Jle3iJb3uqu5m2e7A/DwzpuCAHdiU+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.69.0': - resolution: {integrity: sha512-Ug0+eU7HJBlek+SjklYH62IlOMirEJsdxpihH0kSqX0XdrDD4NdHpQc10fK1JC35yn6KrrcN+uYzlHD38XAf8Q==} + '@oxlint/binding-linux-ppc64-gnu@1.70.0': + resolution: {integrity: sha512-J8VPG7I3/HmgaU4u8pNU2kFx2+0U+vPLS1dXFxXOaR/2TQ0f8AC7DRz0SRGRI1bfphnX2hVYTTtLuhL4nYKL+Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.69.0': - resolution: {integrity: sha512-iEyI3GIg0l/s3G4qy2TlaaWKdzj4PJJStwtlocpDTC00PY9hZueotf6OKUj9+yfQh0lrpBW/pLMgTztbAHKJEg==} + '@oxlint/binding-linux-riscv64-gnu@1.70.0': + resolution: {integrity: sha512-N2+4lV2KLN+oXTIIIwmWDhwkrnvqf5oX7Hw0zPjk+RuIVgiBQSOlJWF7uQoFx2siEYX0ZQ5cfSbEAHm+J3t7Wg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.69.0': - resolution: {integrity: sha512-NjHjpiI4WIKSMwuoJSZi5VToPeoYOS1FR52HLIDG6lidMdqquusgtODb4iLk0+lb1q3Z0nv2/aPRcC/olmpQGg==} + '@oxlint/binding-linux-riscv64-musl@1.70.0': + resolution: {integrity: sha512-1e2L7cFCvx9QDzq6NPP+0tABKb5z6nWHyddWTNKprEsjO9xNrAtPowuCGpjNXxkTdsMiZ4jc8YQ5SstZd4XK6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.69.0': - resolution: {integrity: sha512-Ai/prDewoItkDXbp38gwGZi41DycZbUTZJ3UidwoHgQC0/DaqC2TGdtBTQLJ6hSD+SAxASzh8+/eSBPmxfOacA==} + '@oxlint/binding-linux-s390x-gnu@1.70.0': + resolution: {integrity: sha512-Kwu/l/8GcYibCWA9m9N5pRXMIKVSsL/YbgpLzYkqDhWTiqdRfnNJ/+nqIKRKQiFbHWsdlHEhzMwruJK+qcEruA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.69.0': - resolution: {integrity: sha512-Gt3KHgp46mRKz4sJeaASmKvD8ayXookRw07RMf+NowhEztGGDZ7VrXpoW96XuKJLjFukWizOFVNjmYb/u7caNQ==} + '@oxlint/binding-linux-x64-gnu@1.70.0': + resolution: {integrity: sha512-tap04CsHYOl0nSAQJfPNIuBxqEPB2HnhQqwaOXLg1jnp2XfRo8Fa814dA4QC4zpvTWXCjAAaCY1W5LOORkEQuQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.69.0': - resolution: {integrity: sha512-7tQhJ2+p/oHv1zcfnjYI7YVzC/7iBaVOfIvFYtxdJ5F45mWgEdrCyXZXZGfiLey5t/5JhOhsaMnnv1kAzckd7g==} + '@oxlint/binding-linux-x64-musl@1.70.0': + resolution: {integrity: sha512-hzJa/WgvtJpbBD9rgfy0qe+MjbxOXNUT0bfR1S6EQQzfTtBFA9xg5q8KSwRrQ2QfSS+TaP4j+4mVPQrfNc6UNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.69.0': - resolution: {integrity: sha512-vmWz6TKp/3hfA4lksR0zHBv/6xuX1jhym6eqOjdH2DXsDDHZWcp2f0KG0VCAnlVbIrjk29G4wAWMXb/Hn1YobA==} + '@oxlint/binding-openharmony-arm64@1.70.0': + resolution: {integrity: sha512-xbsaNSNzVSnaJACCUYr1HQMyY/Q/Q1LkePmHG3UvZPvGCYGNxrsZp9OmtA6ick8xH47ltRRbRrPCM1YXYcyC+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.69.0': - resolution: {integrity: sha512-9RExaLgmaw6IoIkU9cTpT71mLfI0xZ86iZH8x518LVsOkjquJMYqb9P7KpC8lgd1t0Dxs41p2pxynq4XR3Ttzw==} + '@oxlint/binding-win32-arm64-msvc@1.70.0': + resolution: {integrity: sha512-icAEsUI7JbW1TMRdEXV83mVAInhRVQYuuAlPpxdGwJ95chNdnCzjloRW8GglT0WvzOEZSio6fnYSk2DJ2Hv7LQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.69.0': - resolution: {integrity: sha512-1907kRPF8/PrcIw1E7LMs9JbVrpgnt/MvFdss3an8oDkYNAACXzTntV3t3869ZZhMZxb2AzRGbz1pA/jdFatXA==} + '@oxlint/binding-win32-ia32-msvc@1.70.0': + resolution: {integrity: sha512-FHMSWbVsPVs/f+Jcl04ws4JJ2wUnauyTzlpxWRG/lSO/8GpX08Fo2gQZqdA6CrRFI+zvkxl+N/KwJGWfUwYVZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.69.0': - resolution: {integrity: sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA==} + '@oxlint/binding-win32-x64-msvc@1.70.0': + resolution: {integrity: sha512-ptOlKwCz7n4AKs5VweMqG6DAg677FmKOK+vBkkL9DMNgFATIQ+upqUYBTOEwRQyRAx1ncGlPlXleV2hIcm3z4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -6237,8 +6241,12 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@playwright/test@1.60.0': - resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@playwright/test@1.61.0': + resolution: {integrity: sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==} engines: {node: '>=18'} hasBin: true @@ -6257,11 +6265,11 @@ packages: '@polka/url@1.0.0-next.25': resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} - '@posthog/core@1.32.3': - resolution: {integrity: sha512-vwOEMfZvGv5XxNWV7p9I52NSmvFNMhyW2IHpIoUHW5jLkgUrknzJW1H/qxVGSIrNNVQkfsoaDFzDhJdg10pgrA==} + '@posthog/core@1.35.3': + resolution: {integrity: sha512-EsGPbSLl39Jgo2KZ+kI9UAxFnh5nddaN5bNm2rXvUwF+vGmam9eN1EXeNbxhRU7ulEeIiGdm7XjoU7pzavkgIQ==} - '@posthog/types@1.386.3': - resolution: {integrity: sha512-LqJoiQi2eyWn7rCUgnn+D+F3Efp6+04o72bjSX6kWHx0nFaYNC/nJuAIRliDTY/X7GPIUAaHAcSjbMI/9wfX1Q==} + '@posthog/types@1.390.2': + resolution: {integrity: sha512-WcfKz2GNn2vfDX8vXmJYbKxegPxVWHuDQ/pHdAn0HoZDXDFnEp/+x3qBQA+fEvtbPjjtjgAt2wIgJMlM7asx7g==} '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -6546,30 +6554,30 @@ packages: '@rvf/set-get@7.0.1': resolution: {integrity: sha512-GkTSn9K1GrTYoTUqlUs36k6nJnzjQaFBTTEIqUYmzBcsGsoJM8xG7EAx2WLHWAA4QzFjcwWUSHQ3vM3Fbw50Tg==} - '@scalar/agent-chat@0.12.10': - resolution: {integrity: sha512-fWCou0STC+/xO41fHnn9+3C6loiWjoIe4qxBY0hP5uor0Fg9rsijjJMtH6bodPTdfuf3eRwzezATkGhj/rHoIw==} + '@scalar/agent-chat@0.12.11': + resolution: {integrity: sha512-JX1rFryU6kHHcMzzewr9o4Qe0st/27A8AFvka7v0OWsIoNJHcO9aA5gitedci6eZJNsNSBj6bXpH5VrCU1jAfA==} engines: {node: '>=22'} - '@scalar/api-client@3.10.3': - resolution: {integrity: sha512-MCoIyDbvg+dl01Wib13J5DyrDQa23n4tVfYBgxAj65dZtttGQctJ7hxwVDuVA5K15IIYwqzKj/7rgKA+GLvYZA==} + '@scalar/api-client@3.10.4': + resolution: {integrity: sha512-TwmbM6hnzPs1vZUzucczNkPTzxTOtV+gu+TIq8/yEZBYF7GC6+6YerxPrGYjTgifp2UbIYf9GlSvmZv8RzSkIQ==} engines: {node: '>=22'} - '@scalar/api-reference-react@0.9.46': - resolution: {integrity: sha512-DQ/sg8d0DZ7wl6A8At1RKTvPrIBZCuNJI2ffRwIcO86NP9SKSw1E/YK7cQsaJIMYtWTYY2ibQisdU4OdlK//Fw==} + '@scalar/api-reference-react@0.9.47': + resolution: {integrity: sha512-2vT7WCgU2AY2wrB+Xit09b76h5uQsQ/zP68LyTKSPYG8FIYeVsuGkrpIJGbtY/f57d3rQCqrbrZjLb30VzuWKw==} engines: {node: '>=22'} peerDependencies: react: ^18.0.0 || ^19.0.0 - '@scalar/api-reference@1.59.3': - resolution: {integrity: sha512-47TGjQRWWyjUh96V1j8jbN7U3vADINgs+fwdoNAco/lPikDIOtUjuHgZjrstmQ8yDzUJsPNp7yKC2tBFr/jGkg==} + '@scalar/api-reference@1.60.0': + resolution: {integrity: sha512-godMRo3E/m6uZtm0zVfDa5xCg1IGD+eEt4uVWzR0v62mbm2O70ZWY9l+ondg8CrPQFsCdtWpWW+nYdzvp1tWTw==} engines: {node: '>=22'} - '@scalar/code-highlight@0.3.5': - resolution: {integrity: sha512-vNXN/O4L/UDOdNsJiqi8Ee0MoZ2g4MtlW+EA8TizWr8XIvf3oWGubbyMlIheCsLF2FRQ7ohBM2MKqEF/N6pnUw==} + '@scalar/code-highlight@0.3.6': + resolution: {integrity: sha512-G/EtLF6a3IFGfIv5b7Uj5v/yXFY9+ktViVkfAkSoWJdHNBNk0S/Rb2OgRq24kp0D2TDXhLYF3E9OSHzquS7WqQ==} engines: {node: '>=22'} - '@scalar/components@0.27.1': - resolution: {integrity: sha512-oHFCcs8g9kdAVCx/7uOX6XCJsbgM1n/pHyXJWy0d1JWbdqYighNd4TMm1So5i59sGFzGtI85PBG22/aIvYCImg==} + '@scalar/components@0.27.2': + resolution: {integrity: sha512-cwIf042ehbD4dZWUIIlXZp0VWvaH7jznj/gpuLEqtuEDla5MrhTWYWj20aufpTpCeGexf1mqgouaWHUZ7lYByQ==} engines: {node: '>=22'} '@scalar/helpers@0.8.2': @@ -6584,8 +6592,8 @@ packages: resolution: {integrity: sha512-w8cDbZhHCzmIblWx92IVWoAXsbI4Fz3m++jiBANTSO1hgphF6UqEPQiCt3wnMPaxaanjMQxjS/iBk1UGXR2EGA==} engines: {node: '>=22'} - '@scalar/oas-utils@0.18.4': - resolution: {integrity: sha512-FqKnQhZCE6umlLNjRC6Ik4MlLzLv6vQr8szVY5b45fCJyRBeIjFTs0Hlx7W2GDe46+s+HU21BxHBVohNMFsJgA==} + '@scalar/oas-utils@0.18.5': + resolution: {integrity: sha512-GLL0DPEaKkIrDmkwY83RDnCKQRuzw1u6MjGlEX5iVs/LDjQRvWnkAz9A5iUrH/YHr+ike5NIl3/WzaEWiz6x6A==} engines: {node: '>=22'} '@scalar/openapi-types@0.9.1': @@ -6596,16 +6604,16 @@ packages: resolution: {integrity: sha512-D5b0rGLLZgmkO9mdW2j/ND1KBlH1u3RCpr87HPxv9P9ZSr6PtM5iLqFOJq0ACiaHjY2mikCrxgDmnUEhTzRpHQ==} engines: {node: '>=22'} - '@scalar/schemas@0.4.3': - resolution: {integrity: sha512-YZ/FcxM5ctZ65m07q5DOOUhuQA5SjZvnoyP6jCCfoiaQ/aVXTDF1vZ1+RMYhKqDwfV/QCW36k0H/38aG/8lNyA==} + '@scalar/schemas@0.5.0': + resolution: {integrity: sha512-aV0PWqFpQft9a6d4Z6HOTHKDaA+K4AquxSPfBDI1c5f6lMe5l3zViww/iBQA/Yw+V1+Y2iwSVzhuxaktC1UiMg==} engines: {node: '>=22'} - '@scalar/sidebar@0.9.22': - resolution: {integrity: sha512-/3u3fEO/Ne+n+ql/bQQOGVgf2xu8XML5ClhK/Hn4s8e9C3/9VkqgIyY5kdCAUOdT1rYlsaYNSQgCZOcISAP2ow==} + '@scalar/sidebar@0.9.23': + resolution: {integrity: sha512-2qC5vh1BGhnARF9/psKr5jPbwWyg4RIfflNmh7q/jHxNyeCrHGr1yyUiV8TsWmURR5ZNMiyUPzHaio4hdAcZNw==} engines: {node: '>=22'} - '@scalar/snippetz@0.9.16': - resolution: {integrity: sha512-d4w7bG+7cV/X5jRf7KJbP5f6YR6R01n9t10SeDofWJti9/TCiIJMIk/C1VVWJ/tps0WbPJST5VvWpCXZ69fhVQ==} + '@scalar/snippetz@0.9.17': + resolution: {integrity: sha512-BC8ai3E9O5TbJwdGTounh9T6BVSTuYJ/BObZ6wfmXxMK/AL7bDfYED5xBqqzucAGpjVUaN0u796w5EHB82ryrQ==} engines: {node: '>=22'} '@scalar/themes@0.16.0': @@ -6615,16 +6623,16 @@ packages: '@scalar/typebox@0.1.3': resolution: {integrity: sha512-lU055AUccECZMIfGA0z/C1StYmboAYIPJLDFBzOO81yXBi35Pxdq+I4fWX6iUZ8qcoHneiLGk9jAUM1rA93iEg==} - '@scalar/types@0.13.3': - resolution: {integrity: sha512-+rtVPVC7UPDGaqvBZY8FjXI5cW2xJtJDVsOGuoevRUBkJb3feSiBkGIZxYy0JkJCl9wVUi/PqGEcut6Nb3RnJw==} + '@scalar/types@0.14.0': + resolution: {integrity: sha512-aS1FvHbKhBC51mWqXmhkPe6lmhCd9+u//DQ1YTiCWOz4/fXAdWfwHvW9UZ7AzzcGwGiCo9diE81xV+UvSI1qIg==} engines: {node: '>=22'} - '@scalar/use-codemirror@0.14.11': - resolution: {integrity: sha512-5wtC4pUjzhy72j3aAueJg+fh9KflevJvXMn0YscsxiDTvqwIzeZcHe1N9VNtvzDXgLblEeBT6D0+Vs+boyExxg==} + '@scalar/use-codemirror@0.14.12': + resolution: {integrity: sha512-m+0tmVOHZVAybbcNEizR3m9RYOLtU59AStRkk29J5qaW4J+tsjrz4BDMceeTpoVawL/lxp2vDvQR+w/gKC3miQ==} engines: {node: '>=22'} - '@scalar/use-hooks@0.4.6': - resolution: {integrity: sha512-WhsTBk3e7R31yHWQWrrr/RVPGpqwY22RPHN3i4zdEv6llxrloDbkHTpwXCDHTnX92v2A7hKESR6JrGsXcKqrQw==} + '@scalar/use-hooks@0.4.7': + resolution: {integrity: sha512-8zajxhnKMJuO1HF36y8TeVuSIol2pueYdRvITZTEY8TuRbnwxrvJZk25II7YpxGMORAEDr0bwNF88Dr+QUfw1w==} engines: {node: '>=22'} '@scalar/use-toasts@0.10.2': @@ -6635,8 +6643,8 @@ packages: resolution: {integrity: sha512-tpmmG+/xRE2Kn9RpflU3AIyZv08v10+E1ZrJCx7z6+/91zHVxy0M73kC1LT4/8PbYNt85ywyC8+n+D99JdMcGA==} engines: {node: '>=20'} - '@scalar/workspace-store@0.54.3': - resolution: {integrity: sha512-WN23jqAsAvDW8C9O0Yypo7rn1PpuRU9JWCLDcQgRH0XM968AgymvKbvFlvkoxAQpPoMC/FTLIixqZfBkkbZTJw==} + '@scalar/workspace-store@0.54.4': + resolution: {integrity: sha512-82ffXzHc/TDR6mr9BSzzRkxOaVG8mHQlWLKnPiv8GiFNETgBTQKv9nELEZQpLcG02cJVgVytl+X/TjgZHRDKAw==} engines: {node: '>=22'} '@schummar/icu-type-parser@1.21.5': @@ -7176,224 +7184,224 @@ packages: peerDependencies: vue: ^2.7.0 || ^3.0.0 - '@testcontainers/mysql@12.0.2': - resolution: {integrity: sha512-FIE8Fxhci5Lml4OlaCdqV0YPd4/Kn/GuJ/k24EVLI0k03eTvVfDuVKPShWtHEO0yEjJxSUOuUKOykn39nF+R2A==} + '@testcontainers/mysql@12.0.3': + resolution: {integrity: sha512-xaub3gaAQKR4Q2/9d8B+81XM8LLTQHPOncCL3Ved04JUUIeTobMt3J36JXv/rvEpnrMpphlKYlmQU0aq48HeZA==} - '@testcontainers/postgresql@12.0.2': - resolution: {integrity: sha512-dHBi6H2+op11hd2EwSdsEKJpf0BTHvtOkNoh/CBLxFrla1kTIqsm3se4CuMma7+yraIdEblW91sSaH9xeV6UOA==} + '@testcontainers/postgresql@12.0.3': + resolution: {integrity: sha512-y0l/ItWxNfdMU783EOZ66lMq90uuuXPqE+fo1jNSRfMbtfUq/9Ez/wluDxxaS+D/i3I0juep+jmz/WVuip8i9Q==} - '@testcontainers/redis@12.0.2': - resolution: {integrity: sha512-Yjb3TkBx1y5/vkI+P/Gv9WDX9obPoqu+9cw65L0tLWHZhzkeoqdTIABmv6m1JFZzZzuuXuRjS1Fd4QkmFlEWyQ==} + '@testcontainers/redis@12.0.3': + resolution: {integrity: sha512-hN3YedOSb6quFzG1IM4j/r/M635GcaYOxzbTuiSN7676BZHrx1VPl+xll3ojk8ds6TvenrfO37lrEVJYN2URlA==} - '@tiptap/core@3.26.1': - resolution: {integrity: sha512-TX9PyPqBoix0qDLjtok/bddtdSy54QhzLVha405C07V+WySOpH3s/pWYkywehZQY0SQtcrcY4MNSCeQjCbA28A==} + '@tiptap/core@3.27.1': + resolution: {integrity: sha512-rV6Qn4wmC6BxfF+4mu6bqGWj9vA4oXXhsrpXaJL2uhjxeHAGofjwcHof2X84VYzeyXgdlsGmqKie4TAppVXZUQ==} peerDependencies: - '@tiptap/pm': 3.26.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-blockquote@3.26.1': - resolution: {integrity: sha512-WaKjKmUaadgvZDDBk9JOn/oidlOFr6booqJIWHGL5S0aUUTKHS19oGfKQq/l9Z1y1niaRePk0Y4fy/jxCnfKPA==} + '@tiptap/extension-blockquote@3.27.1': + resolution: {integrity: sha512-VMF7xJx6qEGiX6DTKNiL31NLqypOcd/4sNjFSe8rb41PwejBJh/nOqVIbBvWkiT6NMGFLxMhj7zJ8/zPo1hXeg==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-bold@3.26.1': - resolution: {integrity: sha512-VIlF2sAiV6K009pcIDotfY8mvsPaq90dxeG9Q0ZIqfMD958TUCqjHw4MGYZf0/FgP12xksBfmcR7W312xgUf9Q==} + '@tiptap/extension-bold@3.27.1': + resolution: {integrity: sha512-TlC5bsS+pqETTrlz4CZz9RO/cKBYtELGIxwtKeivUn3eNfnOxQbbu4WDsiwIfzRFyd0OMnKl6BPM2KnYEehoEQ==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-bubble-menu@3.26.1': - resolution: {integrity: sha512-Y3R9wFKP/U9M04JG+0PM/yW3OV+MSbUp6YBKQWZmUu8x6y7TbcNvDsaJ6QEFZt5aRMS6qH1ksYPTOz47JdjcfA==} + '@tiptap/extension-bubble-menu@3.27.1': + resolution: {integrity: sha512-j/j8Qp9Z5nViade2m7zjrO/CYH/Ca80Qj7aqo0eUaei6FZQ5izlF9o4XQU5EFMAutV6mwynsPUp8FVo5sCuYfw==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-bullet-list@3.26.1': - resolution: {integrity: sha512-JB6bEJJHxXNAXEXTIAN3/j70p1ARHdeMfhzshGZswWKUWtDibTCrspIp7p1VNeiuVtJ/HB6PpFkGi7yWtQ3RTg==} + '@tiptap/extension-bullet-list@3.27.1': + resolution: {integrity: sha512-faCUHnRP47o9Zh9VZZX6EX/569udw9Vopm2PgEKPWuKLE2qaS5WBuUVU0iItdJmKUqaWiOZkpoW4jvnDmj0dfg==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-code-block@3.26.1': - resolution: {integrity: sha512-NY7SYqcrqDVYTSWyaNGdSfCims6pOHoRQ2Rh4DEFb/rb8gLVkqbLZhcHzQCVfinlPqgV3xWF6cYMORwmnlBkXQ==} + '@tiptap/extension-code-block@3.27.1': + resolution: {integrity: sha512-pHlzmZx2OlHfyQ0yRlT5UL4mGokz947DthZuYefN1OleVqOkHpWBG+2JQwqoNq6bmzMne92zbH32rhcJUEYSjA==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-code@3.26.1': - resolution: {integrity: sha512-t9/VR5k3rGPyhcGau9YvVgaAQ+nP9R9WzS996bQQ7GIrMOTSXb0FWwoQFBiYl83V6VA16Tlj/oScC7SFlA8lvA==} + '@tiptap/extension-code@3.27.1': + resolution: {integrity: sha512-epOUpFfEmBzjvnqvjv2qHX7NAuLo5dlOGV690lWu+sAYMjibuJBeVvAiKPyFCfRCCTUxdbDB3jbaOA1yEcEJ7w==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-color@3.26.1': - resolution: {integrity: sha512-f8yy+CBRDqMeaIaQ0UHDbGUqjfGka5O16ja47shatXm49lqLcL06js9tGoiZFVzp9/lcKOLSXjuzxNf0OZ9SbA==} + '@tiptap/extension-color@3.27.1': + resolution: {integrity: sha512-9R/vW4dDTce0E0HU+AyfSkKhz08Hlrx7noRRj3CKrTwsCTR86wReTKFHlzxhLKZiDrJuV2Y7CtNG7KGrAArf+A==} peerDependencies: - '@tiptap/extension-text-style': 3.26.1 + '@tiptap/extension-text-style': 3.27.1 - '@tiptap/extension-document@3.26.1': - resolution: {integrity: sha512-6W2vZjvi0Mv+4xEtwMDGhWwo7FotWR6eKfmntmduvehWevFpMxOKcTtyotjLigfZv738y50YWmvbaPuAPJG3BA==} + '@tiptap/extension-document@3.27.1': + resolution: {integrity: sha512-8FbBTkfnRP4iVaoj+2h3iWa+H0eGDD3yTyVCwrmue/sQTkqUNUoSuAZa3GDG4Sd41xdPwTJxl9nUWGgM1qDCnw==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-dropcursor@3.26.1': - resolution: {integrity: sha512-eVq3BvFIa3YD+pBIlj1i72vYEixlegGVKHnSYiVF2ovkQOSAH9sca7pkq6WgV1sMTCyWCU8e+WznTqtydvHUWA==} + '@tiptap/extension-dropcursor@3.27.1': + resolution: {integrity: sha512-blFf9x9RG0Qr7P3FoAH/033ffa+mMLZn34trVs8Vi0Ppk6FmJAg5HpYFOtmYoeREdNDJ5rHJKV7SoACbOHgskQ==} peerDependencies: - '@tiptap/extensions': 3.26.1 + '@tiptap/extensions': 3.27.1 - '@tiptap/extension-floating-menu@3.26.1': - resolution: {integrity: sha512-xn0g4m/q2bjG+hULPwp6Aqb/6wpzUtc65jOhgJsG/S3Ey3kLJGUvZBuhozwNFu8FcugxM1fMUpNhkJkodCCGFw==} + '@tiptap/extension-floating-menu@3.27.1': + resolution: {integrity: sha512-BmJF1VqB7dSJkgAalrpVFj88WLhxKjcWPuWHOqf2ITrUU2832BhKLXKmxjWUy1gqV8PfNNVWtGfIERy7I0y0+Q==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-gapcursor@3.26.1': - resolution: {integrity: sha512-BWW1yMQQA4TbEU0LLK+4cd9ebLTuZG5KjHwFMBRD/bGiRW9V1gTWFsCqThBbczcANoQiZK9pn5/4Ad/rGM3HUg==} + '@tiptap/extension-gapcursor@3.27.1': + resolution: {integrity: sha512-QoezN0wdvXIwLQ4ee2ccWDaX3RG0lzgQpIMpMz55oPDhpUVax1+19ApsS53LkcktpS4EbnPL4xO4DaJk0Vp7PQ==} peerDependencies: - '@tiptap/extensions': 3.26.1 + '@tiptap/extensions': 3.27.1 - '@tiptap/extension-hard-break@3.26.1': - resolution: {integrity: sha512-gzNb1e/fK6HN+ko1axsrasjK7F1q0Bnm0G4ZY/0eq7pV7s1wZuwoCiGbvUx/9LCFKRV6+94FTqlb0A3NbYN36g==} + '@tiptap/extension-hard-break@3.27.1': + resolution: {integrity: sha512-iv/m9hzl6jfSj9Q8UEjAxONvCoUDaP7M9SRCPx3PaLNxA230TTD6RE0Ye4zFJ8ze7ZVoJJMAqg9Qpq1iYg2JOQ==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-heading@3.26.1': - resolution: {integrity: sha512-eRlv9XxzUL8FobKAiF1WjP35CT2QpbcxxeyYFF7BmGEONvKI7r5g7JGwyGli4Cvclh70h8w6JuoXSmGUVEU65A==} + '@tiptap/extension-heading@3.27.1': + resolution: {integrity: sha512-SrC4l1kEIyv9ZXFaI/8LQqU2MyMmjczw7XXsWUQOTN4YXv0JyVgMNR3cI/wz0d2xsTfBdZ1N85Tdng+Ga1t0Sg==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-highlight@3.26.1': - resolution: {integrity: sha512-qgx4Eetqkogh3OyomZO0yIMQGHhjatCDAtELkC7NQxnmPsp2c9i6ck/hh7mP5We5ccBwUoYRuNGC9lkflCx75g==} + '@tiptap/extension-highlight@3.27.1': + resolution: {integrity: sha512-IeMIUKbW4oyRkgn92BPYQ0fifkbTwVigKwa107nGDHMokz+pHQPFHy8xG3U7gtUOra/8OUo57bFgNGuP0TaH4A==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-horizontal-rule@3.26.1': - resolution: {integrity: sha512-l9lPZYeSmY90y/2GkQcKaICFD5Atr8sx2SzJGkQzpNC9tRxZXyAHnfJE3OjBkspuGzjWIN0DimxBj4ibz58sKw==} + '@tiptap/extension-horizontal-rule@3.27.1': + resolution: {integrity: sha512-QlKE7qn5qMnIGVGhXQlvYedvLtNJ9z0dmit5w8vPb8tKzW4Spk6M7N2kruprrDA8GBwHfeR5wmF+njfUm34qxg==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-image@3.26.1': - resolution: {integrity: sha512-IjoT+kRK4a1sTImvUz257yfk5l9kMxXxfxCfix5AUKdiWyn8SGUjJZapLICcZVY05UDqXmwsBvBK9lHkKX5ERg==} + '@tiptap/extension-image@3.27.1': + resolution: {integrity: sha512-+JTahgQT+NxiGjduaB3qJVyhU/wh4m3pVkht1Earioku2bm/apj5Lb8rSowa/NJYP3B+oQgV/V4YLw5dtDgBoA==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-italic@3.26.1': - resolution: {integrity: sha512-cLKYvOLToWEkJkAPspgIZ/PYDzAxacLm1VWcAq1tO1QDQCDe2Kw+y/zsGlyYEq/aKsAgpp4JNopBwAXRXxt2/A==} + '@tiptap/extension-italic@3.27.1': + resolution: {integrity: sha512-jGGeyn9uRUnNjSTHpbqhiGsp6KaYTSbV09jDXPJI9cDwfV9hpugLvpaCZd0BMBbhU1B1W6kOfX0BE15qX/HQfA==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-link@3.26.1': - resolution: {integrity: sha512-aLLGLgikuhLFHRbjfUC6D4gRg+NUty4uhW7YkyVl8AxxPME47dPbCOX4H6uLCjEZcn3WnfNuCTr6HCTl0KEmGA==} + '@tiptap/extension-link@3.27.1': + resolution: {integrity: sha512-/2jBfsxBZUDGJmpZifqRQPz7f1E5qpS1BckTZ39TADzUJX+feKy7RJ3DtQ02+8y6SSMzvP9loGVjrk6zEMTk4g==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-list-item@3.26.1': - resolution: {integrity: sha512-5gLXJUiP763NA6i4HgrtcwUDXPP8820hsaBQyF1Y1VsXNi02uW9FVLe3RZK8jF0NZUNh9CqD0gogYJCbKOUU8A==} + '@tiptap/extension-list-item@3.27.1': + resolution: {integrity: sha512-zwRl01ETfCkWUvtvK5fw9bXtAajMPkvlkE3Cq6JvH3LF7XXJwDtNj5Tj7exacMpCaSZmlNc43vFb2rAYnrnwMA==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-list-keymap@3.26.1': - resolution: {integrity: sha512-EReSayePO6SIxtRbxx+7KfBQreWHvoZmMb3O/RemfT8W6J0hCG5N/Rh8Z12+YZOnCDRXJ4RzFpAikYka3E54jQ==} + '@tiptap/extension-list-keymap@3.27.1': + resolution: {integrity: sha512-OIMZNlzPSO8WRd4ic73Fxckzl4N1tesjjLL2XApaNA/uMpO0LoF6WSRPAWv+Z24Wp92ARRJAnRP7iZoI5+Jxig==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-list@3.26.1': - resolution: {integrity: sha512-06nOjnyXpzMO8Ys5k3IbYsDsKib1mv2OtaxBYX1/1uvRyOKwUX5tqDLb/qigic0LIANNL73lkNC8Z8XPeG4Tkg==} + '@tiptap/extension-list@3.27.1': + resolution: {integrity: sha512-c2Upru7lj0/ZV/Ibww6cNz6sUS8m6Dp/9uygFhYcZOd3X8M0xBIEk42c6m6SQehkPziVA8QOgNJz7sMqsbz1OQ==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-ordered-list@3.26.1': - resolution: {integrity: sha512-LeFPeFwb7ylkQVuuaHj+niu7WhWHpjDOi1GKZJE/ohOa2lgt7P221HMqhUzPiDlXOExN72oWTNmXUlT0ymCTkw==} + '@tiptap/extension-ordered-list@3.27.1': + resolution: {integrity: sha512-GYrKqD//9nHJ2r80uXqbDMzRnFpGzbaEQRTSGaO/SH7DvXWFMow8evkOdjQ7PCQO07jNjJo75+A85Jwu3Ov3AA==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-paragraph@3.26.1': - resolution: {integrity: sha512-OkBeYUNM3eTzjm3z6IcC3NHryOX8g3eGNI86P/B+tFoFQSRuzLsKZU50ARCfIiLLg812NjcqujeJ1eX3BKDZrw==} + '@tiptap/extension-paragraph@3.27.1': + resolution: {integrity: sha512-7K7eo1gruOgAsnbK+GCV23AUVUI0cL1bTig8HaPneoFMVbig7vddk8jNLKBWO8TXVbG7TuHdnDN4F98vdtwh5Q==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-placeholder@3.26.1': - resolution: {integrity: sha512-oJCEVmaaUY1Jn5v8KbRMdgYLFH9aptLkir+M0ZMnl+8TTmvMdLK2H02X9ofZQwAb12qreQgb890hB3PFen7TDg==} + '@tiptap/extension-placeholder@3.27.1': + resolution: {integrity: sha512-lhcNDcczQ75yJOSywCHb58Hmtg1aPL/2TdYmeLPxVrP048D7rRs133sfONcgyyw0AvhnfmPOkHLTv3QtKSowhw==} peerDependencies: - '@tiptap/extensions': 3.26.1 + '@tiptap/extensions': 3.27.1 - '@tiptap/extension-strike@3.26.1': - resolution: {integrity: sha512-7hmQ2mBsA+75GRrJIKYxb+10H23mblEQSGGsv9Ptl7JLaGmj+8sv2HGQGSUT9QBiBVprxaYTqyWFXQC9akfLWg==} + '@tiptap/extension-strike@3.27.1': + resolution: {integrity: sha512-Y3DW1jlSlCNCyMGHP3+3qBNNPS83wuFz4RTYGjZtvRRTCRh7apZme9XRWMq1rN5mJ2Cr7fKocA2/5Bs13KgN6Q==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-table-cell@3.26.1': - resolution: {integrity: sha512-eCGgHrzIUPHZpz/z3F4O8yk+SM/HBcLVvAWTHl8P+4/GC2+6oVFH+9ixBDIMKiJugSOnuOY8uLm30+Ld/MtyTw==} + '@tiptap/extension-table-cell@3.27.1': + resolution: {integrity: sha512-aopweoHugP+ZR5WTgb7mccXXWmjoNv7PBjtQDl8rvS4IWsJE1w23B+rkj7VuoncO8WK5bU3SS9O3l5aObql68w==} peerDependencies: - '@tiptap/extension-table': 3.26.1 + '@tiptap/extension-table': 3.27.1 - '@tiptap/extension-table-header@3.26.1': - resolution: {integrity: sha512-idVDYdhVpTL4hnzuf/MbE74HHjqqqIRCVwzfbTy/d5JnTnJ1LXpJZKz2oFWNOk5NaAq0kPhkwkz5lSBUgd2DbQ==} + '@tiptap/extension-table-header@3.27.1': + resolution: {integrity: sha512-+J9EyKP6RMInfMJbIoNemqWzHxZe9XZv/7OjpsvtVZO1cxMTd5W1xIg0Ntr7YMdG9eKBC8Vwx5jjFbRm2tbM3A==} peerDependencies: - '@tiptap/extension-table': 3.26.1 + '@tiptap/extension-table': 3.27.1 - '@tiptap/extension-table-row@3.26.1': - resolution: {integrity: sha512-zAr7bQcUHoBpeysvbzxW8JchMduUn0wGwA2UeEgoE1K+gep74wRHs9LE8NRd70hARbZLzgUMRXcpT+W1pdoMMw==} + '@tiptap/extension-table-row@3.27.1': + resolution: {integrity: sha512-peEcbNRrJJ9Qc/WNKQNFbkwBrJvBvq22Dp5WNqEygn/ZJez1qD9ctd10+D6f3b9GtSyx12sfDgn8yBufWa+Iug==} peerDependencies: - '@tiptap/extension-table': 3.26.1 + '@tiptap/extension-table': 3.27.1 - '@tiptap/extension-table@3.26.1': - resolution: {integrity: sha512-epxUhc5ecxsH39lzNejc2WxFPXAXWGs9g2ofKDrIaoSlZlfFHf89/sEGSz048a46E5Sb+fYCtzUvRUUx+aG4xw==} + '@tiptap/extension-table@3.27.1': + resolution: {integrity: sha512-tNB8kjxo0+XPremnWkd6NUikpeJ+JQrss7HntL8GgIxX4t0gkdnLn9yUWb0JzcaYP7Y8iTZZHdkPs0P154DG8Q==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-task-item@3.26.1': - resolution: {integrity: sha512-VjwGkI7MJIswrfkArO4yWS9eAJq2KrCVsNIH96yUGkKve4cHrpDHfbCboLaj8453N98AGVtgY9GdVnAL6ypSAg==} + '@tiptap/extension-task-item@3.27.1': + resolution: {integrity: sha512-HxS85Xqlf9voWpqW6yJNExjnqy9AcQbvL7K41gzKUIaXZdNxAyEkUg7wve7WAd7AUPI9yrS9WONplhmq7pWuJw==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-task-list@3.26.1': - resolution: {integrity: sha512-d5eO6Ae6WqSZHd0lt16snD8u2PlZIjmKuvDQBjPYvzl5MUOmplcuOyaAsaphBJK5tr4u9pP9XDNVGB7Xjp0gHQ==} + '@tiptap/extension-task-list@3.27.1': + resolution: {integrity: sha512-5LaJU3q/O6S1aNe9uj/VbZ7uS8G9mJMvJGNm/wRGyR3HcZtHAcFsPh9+woylQvUThD0qO9OMeGXkgqRSE+ayuA==} peerDependencies: - '@tiptap/extension-list': 3.26.1 + '@tiptap/extension-list': 3.27.1 - '@tiptap/extension-text-align@3.26.1': - resolution: {integrity: sha512-Ptbu1FyASFqIrbw/p9D6zLt8G7seDh4X408qU9FIrun7PE79o+amB5LWI/SzHFuVk3OMI+g7jE/mMDhNUYsqVA==} + '@tiptap/extension-text-align@3.27.1': + resolution: {integrity: sha512-EXawuJBO55wd8WcTbHTMoPhv0CGQxza4yCCPB5Hqz4ZPQwahIr3ej+8yp/kimIl0xokabwZ0/Fu8STQ4AkZv5g==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-text-style@3.26.1': - resolution: {integrity: sha512-V8t7qOyLH7IBR2HjjJVZ9rUHTnuFToJx07L9PN9PpgQLhz9q8Jah4gAwmjLBXDRG2YaXImGK0RwKKCU/yHhwOg==} + '@tiptap/extension-text-style@3.27.1': + resolution: {integrity: sha512-J48WIl+6YDYTFPhWXUBQk+u7+AKVUqTdvrZOQyPYCGuQMgHrYzgWrI5+HeEifUgXJ5rMIWWP3qytp7KhVVqpDQ==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-text@3.26.1': - resolution: {integrity: sha512-Gocui5WvcCCJJIX17gdOVCSdYi5H4fDwaR0qkMAUZPq5kJCdrfl+vNpt8BTt53Bk+/QumiUW21fhQ184w7RoeQ==} + '@tiptap/extension-text@3.27.1': + resolution: {integrity: sha512-6ZwaZwSrDh+KFFv6V1J79oO37yPs7y1bFxvk1/9Ih2rn3Xr5AWz+eMS+n8RpH3djBVVAQpdIAeYQgcn+VCSsTg==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extension-underline@3.26.1': - resolution: {integrity: sha512-HUHtQ+DRWDM0opW7Nk3YQwrLzw876hMU7cr1X/ZTG+8Bp+AKHihlwU+bqrPgG5St0mqASyUEhHQ/vK5PlnUYOQ==} + '@tiptap/extension-underline@3.27.1': + resolution: {integrity: sha512-N889J4nXN/TPfVt8uF9N1A0SY82E90zwc1y26lqOcw6KWNLmQrlhMh/9OD4ikLDbekmFpOBq/UicpHf/6S8hbQ==} peerDependencies: - '@tiptap/core': 3.26.1 + '@tiptap/core': 3.27.1 - '@tiptap/extensions@3.26.1': - resolution: {integrity: sha512-PmRaoe6bebTgz/ZQrjmzwZMST1d9js9ZTiKnUXeXl3Fm+V5U/c3TbbKDfqmL63qPQdjtShDMHi9tYuv+c77OFQ==} + '@tiptap/extensions@3.27.1': + resolution: {integrity: sha512-1Tdx9faw8k0/83V6X+xCDVhV8yElGt95JxeW3YMkKQJI56QdlPz0xOdJPlMiSGJKinPyVier+x9LJD/YZUZIaw==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 - '@tiptap/pm@3.26.1': - resolution: {integrity: sha512-48cJQRbvr9Ux0+IgM1BR5vOLU5hkC+n+uerdQy2JjrIRKpYE/huU8fQFm6PoRppoKYfilklzb29elsQ+n2TA+g==} + '@tiptap/pm@3.27.1': + resolution: {integrity: sha512-Ffjx+vimmBU7zH/KrpXzJid3+pziCe/VL2aexSTP63cyQwKQ65LkFkCKaIsSpFdQQuakVZBGWjCA5RoBV852pw==} - '@tiptap/react@3.26.1': - resolution: {integrity: sha512-Gl7AhTJM7pjQ2WFwdIwD736oQeqUcw3GVaXYmCKtwTSO3F9PszLgeKEp6DvM+CmctTNYhu/apRfzkH3vU0h0uA==} + '@tiptap/react@3.27.1': + resolution: {integrity: sha512-/Wn2fc9zMtX08MXYScDFsm4wJ8lzfhfPEdbtls7WCDlbtrop48PWlkHDBBJrywARfAQTB2mFs9KiFy9yrQm5Lg==} peerDependencies: - '@tiptap/core': 3.26.1 - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1 + '@tiptap/pm': 3.27.1 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@3.26.1': - resolution: {integrity: sha512-A0zsvwGU9exLND34F8e8KqUXFSfs835tNN+VC+ZT3yNeaO/WXnlh/Cgal1F6pHHbcxy7RV2CRwJU5S3cWLPxrA==} + '@tiptap/starter-kit@3.27.1': + resolution: {integrity: sha512-vfxRsqW8rCc0k4pzo0ilU3wobVi2wqVj88VZI2SlgZlNnUAkrDGDIAph7CTa9k9fshV+O1ivpEgPC5yC046jow==} '@trpc/client@11.17.0': resolution: {integrity: sha512-KpJBFrbKTDeVCFv/3ckL1XBBH5Yssn8hethI/rUy7GIpTj+VzjtPjykDqJpzobuVOz+d26cXCSu1t4I6MYI5Zg==} @@ -7859,8 +7867,8 @@ packages: resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} - '@videojs/http-streaming@3.17.4': - resolution: {integrity: sha512-XAvdG2dolBuV2Fx8bu1kjmQ2D4TonGzZH68Pgv/O9xMSFWdZtITSMFismeQLEAtMmGwze8qNJp3RgV+jStrJqg==} + '@videojs/http-streaming@3.17.5': + resolution: {integrity: sha512-PRRQVu0hYW5h0XvRWpIyIpEatpMZzZtf7L1avV89Hnu+69f+0c7oLsSL9jwpg2nbvzGkdX5rQxQkz5Vc7tFR9w==} engines: {node: '>=8', npm: '>=5'} peerDependencies: video.js: ^8.19.0 @@ -7869,6 +7877,10 @@ packages: resolution: {integrity: sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==} engines: {node: '>=8', npm: '>=5'} + '@videojs/vhs-utils@4.1.2': + resolution: {integrity: sha512-1Dsv5dtWOq0LP1G37O46FQFA2tKAZON5UMe6dFPxT7JvPhEx8QIXcFQxan8+hHI3fX6aomFRFrUBJNgRYQDSXA==} + engines: {node: '>=8', npm: '>=5'} + '@videojs/xhr@2.7.0': resolution: {integrity: sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==} @@ -7885,20 +7897,20 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/coverage-v8@4.1.8': - resolution: {integrity: sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==} + '@vitest/coverage-v8@4.1.9': + resolution: {integrity: sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==} peerDependencies: - '@vitest/browser': 4.1.8 - vitest: 4.1.8 + '@vitest/browser': 4.1.9 + vitest: 4.1.9 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.8': - resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + '@vitest/expect@4.1.9': + resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} - '@vitest/mocker@4.1.8': - resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + '@vitest/mocker@4.1.9': + resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -7908,25 +7920,25 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.8': - resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + '@vitest/pretty-format@4.1.9': + resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} - '@vitest/runner@4.1.8': - resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + '@vitest/runner@4.1.9': + resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} - '@vitest/snapshot@4.1.8': - resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + '@vitest/snapshot@4.1.9': + resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} - '@vitest/spy@4.1.8': - resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + '@vitest/spy@4.1.9': + resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} - '@vitest/ui@4.1.8': - resolution: {integrity: sha512-RUS2ZU2TsduVrI+9c12uTNaKrNUTsm6yFt3fueEUB9iKvyC2UP83F+sqIz00HQIah4UOL1TMoDAki8K0NjGvsA==} + '@vitest/ui@4.1.9': + resolution: {integrity: sha512-U/cRvtqfEPj27FI1n9cyUvi4vXXdcLhjJiI+InYKdk8hP4VrS6RXOjGL7rfFaeBc37iRKANsR6eEzIoC7lmgBQ==} peerDependencies: - vitest: 4.1.8 + vitest: 4.1.9 - '@vitest/utils@4.1.8': - resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + '@vitest/utils@4.1.9': + resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} '@vue/compiler-core@3.5.35': resolution: {integrity: sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==} @@ -7969,7 +7981,7 @@ packages: resolution: {integrity: sha512-SDobKBbPIOe0cVL7QxMzGkuUGHvWTdihi9zOrrWaWUgFKe15cwEcwfWmgrcNzjT6kHnNmWuTajPHoIzUjYNYYQ==} peerDependencies: async-validator: ^4 - axios: '>=1.17.0' + axios: '>=1.18.0' change-case: ^5 drauu: ^0.4 focus-trap: ^7 @@ -8239,9 +8251,16 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - archiver@8.0.0: - resolution: {integrity: sha512-fV1orZfsnPn9BaSByR/qE67rJCLJEy2Ox5bq7nJh+jquWaNh6Sfec75kJ2T6PtdGUbPQlrVoSVCEOa5SdiTQ1g==} - engines: {node: '>=18'} + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -8361,6 +8380,9 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.2: resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} engines: {node: 20 || >=22} @@ -8540,6 +8562,9 @@ packages: resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} engines: {node: '>=14.16'} + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} @@ -8846,9 +8871,9 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - compress-commons@7.0.1: - resolution: {integrity: sha512-g0S8KAD8qf4+V//pr3BfB1aBnARLXNz2Gx+jmHU0LEriUuoQUOPOulVquHKTJ8+EAIIO7fhseNDr9wK5Q9FKBQ==} - engines: {node: '>=18'} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} @@ -9012,9 +9037,9 @@ packages: engines: {node: '>=0.8'} hasBin: true - crc32-stream@7.0.1: - resolution: {integrity: sha512-IBWsY8xznyQrcHn8h4bC8/4ErNke5elzgG8GcqF4RFPw6aHkWWRc7Tgw6upjaTX/CT/yQgqYENkxYsTYN+hW2g==} - engines: {node: '>=18'} + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -9534,6 +9559,9 @@ packages: dompurify@3.4.10: resolution: {integrity: sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -10014,8 +10042,8 @@ packages: fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} - fast-xml-parser@5.8.0: - resolution: {integrity: sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==} + fast-xml-parser@5.9.3: + resolution: {integrity: sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==} hasBin: true fastify@5.8.5: @@ -10134,6 +10162,10 @@ packages: debug: optional: true + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + form-data-encoder@2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} @@ -10280,6 +10312,11 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -10894,6 +10931,9 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} + is-unsafe@1.0.1: + resolution: {integrity: sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==} + is-what@5.5.0: resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} engines: {node: '>=18'} @@ -10927,8 +10967,8 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - isomorphic-dompurify@3.17.0: - resolution: {integrity: sha512-++PY22SYWZv/kTWOr5WQ8rNznkIKj6I/SDUVZnXXM67EhRO7ScVLDdZYNxNgEsPAOA5sfpGBcqnnbLx8WJHO1g==} + isomorphic-dompurify@3.18.0: + resolution: {integrity: sha512-ajp0D8laIHeoYlhBTevpE2HUhqWaqLXFk6K/wV3Ok8kDraBZpZsifwVWaY8IfJntMRIo1VSksgKV+lXyet9Q7A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} isomorphic-ws@5.0.0: @@ -10952,6 +10992,9 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.2.3: resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} engines: {node: 20 || >=22} @@ -11312,6 +11355,7 @@ packages: loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -11337,8 +11381,8 @@ packages: resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - lucide-react@1.18.0: - resolution: {integrity: sha512-LZDb7H/0YfM+RJncD0hDQRCAu+vSGODqpe35TuVI8EuXaRjkczbsx7p8dY4J87F/MUSj6bpYqeI8nw8qXaAdmA==} + lucide-react@1.21.0: + resolution: {integrity: sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -11355,8 +11399,8 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - mantine-datatable@9.3.0: - resolution: {integrity: sha512-YCLC5VCRPUHDoDUvWgVY81bx17MDk3Gz38icOINe/QO2ZKASGxNzf/wiqV3Dv1N/BRO601GyVMHRH6LzFWVC7g==} + mantine-datatable@9.3.1: + resolution: {integrity: sha512-w+KtNCUcNypgmpwYlbYF9zDb0e5gNFE5YI3ZrgE+9ISJxg/8hpmWyprA4YVMbKY8mC80zwOwaKoew5lLx0esoA==} peerDependencies: '@mantine/core': '>=9.0' '@mantine/hooks': '>=9.0' @@ -11724,6 +11768,14 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -11739,8 +11791,8 @@ packages: engines: {node: '>=10'} hasBin: true - mpd-parser@1.3.1: - resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==} + mpd-parser@1.4.0: + resolution: {integrity: sha512-blbA7XpAaOdC/PR0Tu8GiUxlx6CpBuRowQPYV7lhi9Yr9G9+dkPXIUjqjzc/NCn/uZZPopluaJlIYntIEI/VLw==} hasBin: true mrmime@2.0.0: @@ -11804,6 +11856,11 @@ packages: engines: {node: ^18 || >=20} hasBin: true + nanoid@5.1.15: + resolution: {integrity: sha512-kBg3RpGtIe+RpTbyXwoI6pk5yD7KUiI3sygUqgeBMRst42KmhB4RZC7eiO9Wa1HIpaCCtpE2DJ6OI4Wi5ebwFw==} + engines: {node: ^18 || >=20} + hasBin: true + nanostores@1.3.0: resolution: {integrity: sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==} engines: {node: ^20.0.0 || >=22.0.0} @@ -12125,8 +12182,8 @@ packages: outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - oxfmt@0.54.0: - resolution: {integrity: sha512-DjnMwn7smSLF+Mc2+pRItnuPftm/dkUFpY/d4+33y9TfKrsHZo8GLhmUg9BrOIUEy94Rlom1Q11N6vuhE+e0oQ==} + oxfmt@0.55.0: + resolution: {integrity: sha512-jSj2wCTakwgPMxkfiVZX0jf+nX+Nz6xlyAZjqNE0qXTFdCBPYlP6JAN+ODjmealw7DXBjOzYbdsqwBMAZnPZ6A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -12138,8 +12195,8 @@ packages: vite-plus: optional: true - oxlint@1.69.0: - resolution: {integrity: sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==} + oxlint@1.70.0: + resolution: {integrity: sha512-D6JgHtzkhRwvEC+A0Nw5AEc5bk8x5i1pHzvZIEf/a0C4hOzmAACNGtkDGPyFaxxX3ZVGxCPeig3P3rMM8XU3/g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -12215,6 +12272,9 @@ packages: resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} engines: {node: '>=4'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-json@8.1.1: resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} engines: {node: '>=14.16'} @@ -12322,6 +12382,10 @@ packages: resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==} engines: {node: '>=0.10.0'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -12351,8 +12415,8 @@ packages: pg-cloudflare@1.4.0: resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} - pg-connection-string@2.13.0: - resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} + pg-connection-string@2.14.0: + resolution: {integrity: sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} @@ -12363,15 +12427,15 @@ packages: peerDependencies: pg: '>=8.0' - pg-protocol@1.14.0: - resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} + pg-protocol@1.15.0: + resolution: {integrity: sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.21.0: - resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==} + pg@8.22.0: + resolution: {integrity: sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -12431,13 +12495,13 @@ packages: resolution: {integrity: sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==} engines: {node: '>=16.0.0'} - playwright-core@1.60.0: - resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + playwright-core@1.61.0: + resolution: {integrity: sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==} engines: {node: '>=18'} hasBin: true - playwright@1.60.0: - resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + playwright@1.61.0: + resolution: {integrity: sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==} engines: {node: '>=18'} hasBin: true @@ -12894,8 +12958,8 @@ packages: resolution: {integrity: sha512-Ray65LYEJrMMqDtsBUBXunEVP/g4wtATvq/xz9rchUoLy/9mSkkFgUko/8DVtGxgiP3vivpFMgfb9HpCuDrBHg==} engines: {node: '>=10.15.1'} - posthog-js@1.386.6: - resolution: {integrity: sha512-xRcbToRtU07Ojk+VaCCos6I/zD60sNKfWxdeZih0xbncgegIqLZJmBzi4HdkSkXrf14b6HhwMI/s2GxWha5ADQ==} + posthog-js@1.391.2: + resolution: {integrity: sha512-q0DZN6ljchSnAFJIXf+sQFTPlsLjTlRa+TvrL+QRb6413BGtib/MNiQy1bnwLKt8KR+f6xJYvkqdLyty9s4Aww==} posthog-node@4.18.0: resolution: {integrity: sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw==} @@ -13276,9 +13340,8 @@ packages: resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readdir-glob@3.0.0: - resolution: {integrity: sha512-AhNB2KgKeVJr16nK9LLZbJNWnYoT23ZrumNKFDebHBdkC8KHSqWo871JAUhoWC/RtjEVdqNMFpM6qrwRbaUqpw==} - engines: {node: '>=18'} + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -13964,8 +14027,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strnum@2.3.0: - resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} + strnum@2.4.1: + resolution: {integrity: sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==} style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} @@ -14149,8 +14212,8 @@ packages: resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} - testcontainers@12.0.2: - resolution: {integrity: sha512-UNkC3cSGrsNyyDShaES1/tUHqPNQiH7aUXBPYMO2iAY4tdCI2uVdEagBCrLN0RQ1qxDPWU733OuEaDNQs0vanw==} + testcontainers@12.0.3: + resolution: {integrity: sha512-6vfiL9CWIX0rWhTJitzrzHcv4Q/sUfUdBV12jMz6HZ58Lz6ZtXVecO6jljd1O3ookEWQHNICiYoYNEPpDLzuRw==} text-decoder@1.2.0: resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} @@ -14185,9 +14248,8 @@ packages: resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} engines: {node: '>=12'} - timezones-ical-library@2.2.0: - resolution: {integrity: sha512-D8pKEBzYnCAGZSEyinMZqh2yTc7ZJqonXtNkpTzhPuJlkJjPEUJOXBs7ExeHcHGBaGpaJRTye5t0mLR20BeklA==} - engines: {node: '>=22.18.0', npm: '>=10.9.3'} + timezones-ical-library@2.2.1: + resolution: {integrity: sha512-VfDloy50AHsckqwuqc2ea+uyqxY7RjKXOqFMBd4T1zLkq31aVQNKhASvIF4+hSE2tuqaUGzGi4UQk5VzVNn94A==} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -14647,8 +14709,8 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - video.js@8.23.7: - resolution: {integrity: sha512-cG4HOygYt+Z8j6Sf5DuK6OgEOoM+g9oGP6vpqoZRaD13aHE4PMITbyjJUXZcIQbgB0wJEadBRaVm5lJIzo2jAA==} + video.js@8.23.9: + resolution: {integrity: sha512-3UCqyFW4wIusQu4TuhgRUxqtbzbj0WPT9hps0XIEXST43QBD11zb+bG7tBPrinrZztwVYdXCiOBo2pcGj9L05w==} videojs-contrib-quality-levels@4.1.0: resolution: {integrity: sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==} @@ -14710,20 +14772,20 @@ packages: yaml: optional: true - vitest@4.1.8: - resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + vitest@4.1.9: + resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.8 - '@vitest/browser-preview': 4.1.8 - '@vitest/browser-webdriverio': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 - '@vitest/coverage-v8': 4.1.8 - '@vitest/ui': 4.1.8 + '@vitest/browser-playwright': 4.1.9 + '@vitest/browser-preview': 4.1.9 + '@vitest/browser-webdriverio': 4.1.9 + '@vitest/coverage-istanbul': 4.1.9 + '@vitest/coverage-v8': 4.1.9 + '@vitest/ui': 4.1.9 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -15065,9 +15127,9 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} - zip-stream@7.0.5: - resolution: {integrity: sha512-dSvYKdvLsAHCDqPOhIwk/q5CvuWtTB3Dgpoe0uVEFjTzIOAmsQpprX25InCvrvJsirEbu1OHyy67n/kAj1Sw/w==} - engines: {node: '>=18'} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} zod-form-data@3.0.2: resolution: {integrity: sha512-iN8oSINKqNHJ90T+SHUvHg2gfvF+gyVvg4nK1RYYhMUDUpUWaqwqawLbJNDxxrM59pgE0kdcMfqKVwK55Bm5cw==} @@ -16135,12 +16197,12 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 - '@better-auth/drizzle-adapter@1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))': + '@better-auth/drizzle-adapter@1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))': dependencies: '@better-auth/core': 1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/utils': 0.4.1 optionalDependencies: - drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) '@better-auth/kysely-adapter@1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(kysely@0.29.2)': dependencies: @@ -16632,7 +16694,7 @@ snapshots: rfc4648: 1.5.4 uint8array-extras: 1.5.0 - '@ctrl/qbittorrent@9.12.2': + '@ctrl/qbittorrent@9.14.0': dependencies: '@ctrl/magnet-link': 4.3.0 '@ctrl/shared-torrent': 6.5.1(ofetch@1.5.1) @@ -17979,7 +18041,7 @@ snapshots: '@extractus/feed-extractor@7.2.1': dependencies: '@pwshub/bellajs': 13.0.2 - fast-xml-parser: 5.8.0 + fast-xml-parser: 5.9.3 html-entities: 2.6.0 '@fastify/ajv-compiler@4.0.5': @@ -18089,10 +18151,10 @@ snapshots: '@formatjs/fast-memoize': 3.1.0 tslib: 2.8.1 - '@gfazioli/mantine-onboarding-tour@4.0.4(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@gfazioli/mantine-onboarding-tour@4.0.5(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) '@tabler/icons-react': 3.44.0(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -18439,6 +18501,15 @@ snapshots: '@ioredis/commands@1.10.0': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/cliui@9.0.0': {} '@jellyfin/sdk@0.13.0(axios@1.15.0)': @@ -18709,22 +18780,22 @@ snapshots: js-base64: 3.7.8 optional: true - '@mantine/charts@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1))': + '@mantine/charts@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(recharts@3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1))': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) recharts: 3.8.1(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1) - '@mantine/colors-generator@9.3.1(chroma-js@3.2.0)': + '@mantine/colors-generator@9.3.2(chroma-js@3.2.0)': dependencies: chroma-js: 3.2.0 - '@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@floating-ui/react': 0.27.19(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) clsx: 2.1.1 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -18734,68 +18805,68 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) clsx: 2.1.1 dayjs: 1.11.21 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@mantine/dropzone@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/dropzone@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-dropzone: 15.0.0(react@19.2.7) - '@mantine/form@9.3.1(react@19.2.7)': + '@mantine/form@9.3.2(react@19.2.7)': dependencies: '@standard-schema/spec': 1.1.0 fast-deep-equal: 3.1.3 klona: 2.0.6 react: 19.2.7 - '@mantine/hooks@9.3.1(react@19.2.7)': + '@mantine/hooks@9.3.2(react@19.2.7)': dependencies: react: 19.2.7 - '@mantine/modals@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/modals@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@mantine/notifications@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/notifications@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) - '@mantine/store': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) + '@mantine/store': 9.3.2(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-transition-group: 4.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/spotlight@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/spotlight@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) - '@mantine/store': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) + '@mantine/store': 9.3.2(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - '@mantine/store@9.3.1(react@19.2.7)': + '@mantine/store@9.3.2(react@19.2.7)': dependencies: react: 19.2.7 - '@mantine/tiptap@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tiptap/extension-link@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))(@tiptap/react@3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@mantine/tiptap@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tiptap/extension-link@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))(@tiptap/react@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) - '@tiptap/extension-link': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/react': 3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) + '@tiptap/extension-link': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/react': 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -19105,7 +19176,7 @@ snapshots: '@noble/hashes@2.0.1': {} - '@nodable/entities@2.1.0': {} + '@nodable/entities@2.2.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -19289,118 +19360,118 @@ snapshots: '@oxc-project/types@0.133.0': {} - '@oxfmt/binding-android-arm-eabi@0.54.0': + '@oxfmt/binding-android-arm-eabi@0.55.0': optional: true - '@oxfmt/binding-android-arm64@0.54.0': + '@oxfmt/binding-android-arm64@0.55.0': optional: true - '@oxfmt/binding-darwin-arm64@0.54.0': + '@oxfmt/binding-darwin-arm64@0.55.0': optional: true - '@oxfmt/binding-darwin-x64@0.54.0': + '@oxfmt/binding-darwin-x64@0.55.0': optional: true - '@oxfmt/binding-freebsd-x64@0.54.0': + '@oxfmt/binding-freebsd-x64@0.55.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.55.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.54.0': + '@oxfmt/binding-linux-arm-musleabihf@0.55.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.54.0': + '@oxfmt/binding-linux-arm64-gnu@0.55.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.54.0': + '@oxfmt/binding-linux-arm64-musl@0.55.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.54.0': + '@oxfmt/binding-linux-ppc64-gnu@0.55.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.54.0': + '@oxfmt/binding-linux-riscv64-gnu@0.55.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.54.0': + '@oxfmt/binding-linux-riscv64-musl@0.55.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.54.0': + '@oxfmt/binding-linux-s390x-gnu@0.55.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.54.0': + '@oxfmt/binding-linux-x64-gnu@0.55.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.54.0': + '@oxfmt/binding-linux-x64-musl@0.55.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.54.0': + '@oxfmt/binding-openharmony-arm64@0.55.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.54.0': + '@oxfmt/binding-win32-arm64-msvc@0.55.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.54.0': + '@oxfmt/binding-win32-ia32-msvc@0.55.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.54.0': + '@oxfmt/binding-win32-x64-msvc@0.55.0': optional: true - '@oxlint/binding-android-arm-eabi@1.69.0': + '@oxlint/binding-android-arm-eabi@1.70.0': optional: true - '@oxlint/binding-android-arm64@1.69.0': + '@oxlint/binding-android-arm64@1.70.0': optional: true - '@oxlint/binding-darwin-arm64@1.69.0': + '@oxlint/binding-darwin-arm64@1.70.0': optional: true - '@oxlint/binding-darwin-x64@1.69.0': + '@oxlint/binding-darwin-x64@1.70.0': optional: true - '@oxlint/binding-freebsd-x64@1.69.0': + '@oxlint/binding-freebsd-x64@1.70.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.69.0': + '@oxlint/binding-linux-arm-gnueabihf@1.70.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.69.0': + '@oxlint/binding-linux-arm-musleabihf@1.70.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.69.0': + '@oxlint/binding-linux-arm64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.69.0': + '@oxlint/binding-linux-arm64-musl@1.70.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.69.0': + '@oxlint/binding-linux-ppc64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.69.0': + '@oxlint/binding-linux-riscv64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.69.0': + '@oxlint/binding-linux-riscv64-musl@1.70.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.69.0': + '@oxlint/binding-linux-s390x-gnu@1.70.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.69.0': + '@oxlint/binding-linux-x64-gnu@1.70.0': optional: true - '@oxlint/binding-linux-x64-musl@1.69.0': + '@oxlint/binding-linux-x64-musl@1.70.0': optional: true - '@oxlint/binding-openharmony-arm64@1.69.0': + '@oxlint/binding-openharmony-arm64@1.70.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.69.0': + '@oxlint/binding-win32-arm64-msvc@1.70.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.69.0': + '@oxlint/binding-win32-ia32-msvc@1.70.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.69.0': + '@oxlint/binding-win32-x64-msvc@1.70.0': optional: true '@panva/hkdf@1.2.1': {} @@ -19568,9 +19639,12 @@ snapshots: '@pinojs/redact@0.4.0': {} - '@playwright/test@1.60.0': + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.61.0': dependencies: - playwright: 1.60.0 + playwright: 1.61.0 '@pnpm/config.env-replace@1.1.0': {} @@ -19586,11 +19660,11 @@ snapshots: '@polka/url@1.0.0-next.25': {} - '@posthog/core@1.32.3': + '@posthog/core@1.35.3': dependencies: - '@posthog/types': 1.386.3 + '@posthog/types': 1.390.2 - '@posthog/types@1.386.3': {} + '@posthog/types@1.390.2': {} '@protobufjs/aspromise@1.1.2': {} @@ -19805,21 +19879,21 @@ snapshots: '@rvf/set-get@7.0.1': {} - '@scalar/agent-chat@0.12.10(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': + '@scalar/agent-chat@0.12.11(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': dependencies: '@ai-sdk/vue': 3.0.33(vue@3.5.35(typescript@6.0.3))(zod@4.4.3) - '@scalar/api-client': 3.10.3(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3) - '@scalar/components': 0.27.1(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/api-client': 3.10.4(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/components': 0.27.2(tailwindcss@4.3.1)(typescript@6.0.3) '@scalar/helpers': 0.8.2 '@scalar/icons': 0.7.3(typescript@6.0.3) '@scalar/json-magic': 0.12.16 '@scalar/openapi-types': 0.9.1 - '@scalar/schemas': 0.4.3 + '@scalar/schemas': 0.5.0 '@scalar/themes': 0.16.0 - '@scalar/types': 0.13.3 + '@scalar/types': 0.14.0 '@scalar/use-toasts': 0.10.2(typescript@6.0.3) '@scalar/validation': 0.6.0 - '@scalar/workspace-store': 0.54.3(typescript@6.0.3) + '@scalar/workspace-store': 0.54.4(typescript@6.0.3) '@vueuse/core': 13.9.0(vue@3.5.35(typescript@6.0.3)) ai: 6.0.33(zod@4.4.3) js-base64: 3.7.8 @@ -19843,25 +19917,25 @@ snapshots: - universal-cookie - zod - '@scalar/api-client@3.10.3(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)': + '@scalar/api-client@3.10.4(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)': dependencies: '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.3.1) '@headlessui/vue': 1.7.23(vue@3.5.35(typescript@6.0.3)) - '@scalar/components': 0.27.1(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/components': 0.27.2(tailwindcss@4.3.1)(typescript@6.0.3) '@scalar/helpers': 0.8.2 '@scalar/icons': 0.7.3(typescript@6.0.3) '@scalar/json-magic': 0.12.16 - '@scalar/oas-utils': 0.18.4(typescript@6.0.3) + '@scalar/oas-utils': 0.18.5(typescript@6.0.3) '@scalar/openapi-types': 0.9.1 - '@scalar/sidebar': 0.9.22(tailwindcss@4.3.1)(typescript@6.0.3) - '@scalar/snippetz': 0.9.16 + '@scalar/sidebar': 0.9.23(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/snippetz': 0.9.17 '@scalar/themes': 0.16.0 '@scalar/typebox': 0.1.3 - '@scalar/types': 0.13.3 - '@scalar/use-codemirror': 0.14.11(typescript@6.0.3) - '@scalar/use-hooks': 0.4.6(typescript@6.0.3) + '@scalar/types': 0.14.0 + '@scalar/use-codemirror': 0.14.12(typescript@6.0.3) + '@scalar/use-hooks': 0.4.7(typescript@6.0.3) '@scalar/use-toasts': 0.10.2(typescript@6.0.3) - '@scalar/workspace-store': 0.54.3(typescript@6.0.3) + '@scalar/workspace-store': 0.54.4(typescript@6.0.3) '@types/har-format': 1.2.16 '@vueuse/core': 13.9.0(vue@3.5.35(typescript@6.0.3)) '@vueuse/integrations': 13.9.0(focus-trap@7.8.0)(fuse.js@7.4.2)(nprogress@0.2.0)(vue@3.5.35(typescript@6.0.3)) @@ -19892,10 +19966,10 @@ snapshots: - typescript - universal-cookie - '@scalar/api-reference-react@0.9.46(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': + '@scalar/api-reference-react@0.9.47(nprogress@0.2.0)(react@19.2.7)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': dependencies: - '@scalar/api-reference': 1.59.3(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) - '@scalar/types': 0.13.3 + '@scalar/api-reference': 1.60.0(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) + '@scalar/types': 0.14.0 react: 19.2.7 transitivePeerDependencies: - '@vue/composition-api' @@ -19914,25 +19988,25 @@ snapshots: - universal-cookie - zod - '@scalar/api-reference@1.59.3(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': + '@scalar/api-reference@1.60.0(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3)': dependencies: '@headlessui/vue': 1.7.23(vue@3.5.35(typescript@6.0.3)) - '@scalar/agent-chat': 0.12.10(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) - '@scalar/api-client': 3.10.3(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3) - '@scalar/code-highlight': 0.3.5 - '@scalar/components': 0.27.1(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/agent-chat': 0.12.11(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3)(zod@4.4.3) + '@scalar/api-client': 3.10.4(nprogress@0.2.0)(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/code-highlight': 0.3.6 + '@scalar/components': 0.27.2(tailwindcss@4.3.1)(typescript@6.0.3) '@scalar/helpers': 0.8.2 '@scalar/icons': 0.7.3(typescript@6.0.3) - '@scalar/oas-utils': 0.18.4(typescript@6.0.3) - '@scalar/schemas': 0.4.3 - '@scalar/sidebar': 0.9.22(tailwindcss@4.3.1)(typescript@6.0.3) - '@scalar/snippetz': 0.9.16 + '@scalar/oas-utils': 0.18.5(typescript@6.0.3) + '@scalar/schemas': 0.5.0 + '@scalar/sidebar': 0.9.23(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/snippetz': 0.9.17 '@scalar/themes': 0.16.0 - '@scalar/types': 0.13.3 - '@scalar/use-hooks': 0.4.6(typescript@6.0.3) + '@scalar/types': 0.14.0 + '@scalar/use-hooks': 0.4.7(typescript@6.0.3) '@scalar/use-toasts': 0.10.2(typescript@6.0.3) '@scalar/validation': 0.6.0 - '@scalar/workspace-store': 0.54.3(typescript@6.0.3) + '@scalar/workspace-store': 0.54.4(typescript@6.0.3) '@unhead/vue': 2.1.15(vue@3.5.35(typescript@6.0.3)) '@vueuse/core': 13.9.0(vue@3.5.35(typescript@6.0.3)) fuse.js: 7.4.2 @@ -19957,7 +20031,7 @@ snapshots: - universal-cookie - zod - '@scalar/code-highlight@0.3.5': + '@scalar/code-highlight@0.3.6': dependencies: hast-util-to-text: 4.0.2 highlight.js: 11.11.1 @@ -19977,17 +20051,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@scalar/components@0.27.1(tailwindcss@4.3.1)(typescript@6.0.3)': + '@scalar/components@0.27.2(tailwindcss@4.3.1)(typescript@6.0.3)': dependencies: '@floating-ui/utils': 0.2.10 '@floating-ui/vue': 1.1.9(vue@3.5.35(typescript@6.0.3)) '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.3.1) '@headlessui/vue': 1.7.23(vue@3.5.35(typescript@6.0.3)) - '@scalar/code-highlight': 0.3.5 + '@scalar/code-highlight': 0.3.6 '@scalar/helpers': 0.8.2 '@scalar/icons': 0.7.3(typescript@6.0.3) '@scalar/themes': 0.16.0 - '@scalar/use-hooks': 0.4.6(typescript@6.0.3) + '@scalar/use-hooks': 0.4.7(typescript@6.0.3) '@vueuse/core': 13.9.0(vue@3.5.35(typescript@6.0.3)) cva: 1.0.0-beta.4(typescript@6.0.3) radix-vue: 1.9.17(vue@3.5.35(typescript@6.0.3)) @@ -20016,12 +20090,12 @@ snapshots: pathe: 2.0.3 yaml: 2.9.0 - '@scalar/oas-utils@0.18.4(typescript@6.0.3)': + '@scalar/oas-utils@0.18.5(typescript@6.0.3)': dependencies: '@scalar/helpers': 0.8.2 '@scalar/themes': 0.16.0 - '@scalar/types': 0.13.3 - '@scalar/workspace-store': 0.54.3(typescript@6.0.3) + '@scalar/types': 0.14.0 + '@scalar/workspace-store': 0.54.4(typescript@6.0.3) flatted: 3.4.2 vue: 3.5.35(typescript@6.0.3) yaml: 2.9.0 @@ -20034,19 +20108,19 @@ snapshots: dependencies: '@scalar/openapi-types': 0.9.1 - '@scalar/schemas@0.4.3': + '@scalar/schemas@0.5.0': dependencies: '@scalar/helpers': 0.8.2 '@scalar/validation': 0.6.0 - '@scalar/sidebar@0.9.22(tailwindcss@4.3.1)(typescript@6.0.3)': + '@scalar/sidebar@0.9.23(tailwindcss@4.3.1)(typescript@6.0.3)': dependencies: - '@scalar/components': 0.27.1(tailwindcss@4.3.1)(typescript@6.0.3) + '@scalar/components': 0.27.2(tailwindcss@4.3.1)(typescript@6.0.3) '@scalar/helpers': 0.8.2 '@scalar/icons': 0.7.3(typescript@6.0.3) '@scalar/themes': 0.16.0 - '@scalar/use-hooks': 0.4.6(typescript@6.0.3) - '@scalar/workspace-store': 0.54.3(typescript@6.0.3) + '@scalar/use-hooks': 0.4.7(typescript@6.0.3) + '@scalar/workspace-store': 0.54.4(typescript@6.0.3) vue: 3.5.35(typescript@6.0.3) transitivePeerDependencies: - '@vue/composition-api' @@ -20054,10 +20128,10 @@ snapshots: - tailwindcss - typescript - '@scalar/snippetz@0.9.16': + '@scalar/snippetz@0.9.17': dependencies: '@scalar/helpers': 0.8.2 - '@scalar/types': 0.13.3 + '@scalar/types': 0.14.0 js-base64: 3.7.8 stringify-object: 6.0.0 @@ -20067,14 +20141,14 @@ snapshots: '@scalar/typebox@0.1.3': {} - '@scalar/types@0.13.3': + '@scalar/types@0.14.0': dependencies: '@scalar/helpers': 0.8.2 nanoid: 5.1.11 type-fest: 5.6.0 zod: 4.4.3 - '@scalar/use-codemirror@0.14.11(typescript@6.0.3)': + '@scalar/use-codemirror@0.14.12(typescript@6.0.3)': dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/commands': 6.10.3 @@ -20094,7 +20168,7 @@ snapshots: transitivePeerDependencies: - typescript - '@scalar/use-hooks@0.4.6(typescript@6.0.3)': + '@scalar/use-hooks@0.4.7(typescript@6.0.3)': dependencies: '@scalar/use-toasts': 0.10.2(typescript@6.0.3) '@scalar/validation': 0.6.0 @@ -20114,15 +20188,15 @@ snapshots: '@scalar/validation@0.6.0': {} - '@scalar/workspace-store@0.54.3(typescript@6.0.3)': + '@scalar/workspace-store@0.54.4(typescript@6.0.3)': dependencies: '@scalar/helpers': 0.8.2 '@scalar/json-magic': 0.12.16 '@scalar/openapi-upgrader': 0.2.9 - '@scalar/schemas': 0.4.3 - '@scalar/snippetz': 0.9.16 + '@scalar/schemas': 0.5.0 + '@scalar/snippetz': 0.9.17 '@scalar/typebox': 0.1.3 - '@scalar/types': 0.13.3 + '@scalar/types': 0.14.0 '@scalar/validation': 0.6.0 js-base64: 3.7.8 type-fest: 5.6.0 @@ -20605,10 +20679,10 @@ snapshots: '@tanstack/react-query': 5.101.0(react@19.2.7) react: 19.2.7 - '@tanstack/react-query-next-experimental@5.101.0(@tanstack/react-query@5.101.0(react@19.2.7))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)': + '@tanstack/react-query-next-experimental@5.101.0(@tanstack/react-query@5.101.0(react@19.2.7))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)': dependencies: '@tanstack/react-query': 5.101.0(react@19.2.7) - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: 19.2.7 '@tanstack/react-query@5.101.0(react@19.2.7)': @@ -20639,189 +20713,189 @@ snapshots: '@tanstack/virtual-core': 3.17.0 vue: 3.5.35(typescript@6.0.3) - '@testcontainers/mysql@12.0.2': + '@testcontainers/mysql@12.0.3': dependencies: - testcontainers: 12.0.2 + testcontainers: 12.0.3 transitivePeerDependencies: - bare-buffer - supports-color - '@testcontainers/postgresql@12.0.2': + '@testcontainers/postgresql@12.0.3': dependencies: - testcontainers: 12.0.2 + testcontainers: 12.0.3 transitivePeerDependencies: - bare-buffer - supports-color - '@testcontainers/redis@12.0.2': + '@testcontainers/redis@12.0.3': dependencies: - testcontainers: 12.0.2 + testcontainers: 12.0.3 transitivePeerDependencies: - bare-buffer - supports-color - '@tiptap/core@3.26.1(@tiptap/pm@3.26.1)': + '@tiptap/core@3.27.1(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/pm': 3.26.1 + '@tiptap/pm': 3.27.1 - '@tiptap/extension-blockquote@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-blockquote@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-bold@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-bold@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-bubble-menu@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-bubble-menu@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 optional: true - '@tiptap/extension-bullet-list@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-bullet-list@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-code-block@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-code-block@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 - '@tiptap/extension-code@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-code@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-color@3.26.1(@tiptap/extension-text-style@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)))': + '@tiptap/extension-color@3.27.1(@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)))': dependencies: - '@tiptap/extension-text-style': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) + '@tiptap/extension-text-style': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) - '@tiptap/extension-document@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-document@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-dropcursor@3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-dropcursor@3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extensions': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-floating-menu@3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-floating-menu@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 optional: true - '@tiptap/extension-gapcursor@3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-gapcursor@3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extensions': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-hard-break@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-hard-break@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-heading@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-heading@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-highlight@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-highlight@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-horizontal-rule@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-horizontal-rule@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 - '@tiptap/extension-image@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-image@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-italic@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-italic@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-link@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-link@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 linkifyjs: 4.3.3 - '@tiptap/extension-list-item@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-list-item@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-list-keymap@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-list-keymap@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 - '@tiptap/extension-ordered-list@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-ordered-list@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-paragraph@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-paragraph@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-placeholder@3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-placeholder@3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extensions': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-strike@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-strike@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-table-cell@3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-table-cell@3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-table': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-table': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-table-header@3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-table-header@3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-table': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-table': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-table-row@3.26.1(@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-table-row@3.27.1(@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-table': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-table': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-table@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extension-table@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 - '@tiptap/extension-task-item@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-task-item@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-task-list@3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1))': + '@tiptap/extension-task-list@3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) - '@tiptap/extension-text-align@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-text-align@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-text-style@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-text-style@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-text@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-text@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extension-underline@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))': + '@tiptap/extension-underline@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) - '@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)': + '@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 - '@tiptap/pm@3.26.1': + '@tiptap/pm@3.27.1': dependencies: prosemirror-changeset: 2.3.0 prosemirror-commands: 1.6.2 @@ -20837,10 +20911,10 @@ snapshots: prosemirror-transform: 1.12.0 prosemirror-view: 1.41.8 - '@tiptap/react@3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@tiptap/react@3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 '@types/react': 19.2.17 '@types/react-dom': 19.2.3(@types/react@19.2.17) '@types/use-sync-external-store': 0.0.6 @@ -20849,48 +20923,48 @@ snapshots: react-dom: 19.2.7(react@19.2.7) use-sync-external-store: 1.6.0(react@19.2.7) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/extension-floating-menu': 3.26.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) + '@tiptap/extension-bubble-menu': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-floating-menu': 3.27.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/starter-kit@3.26.1': + '@tiptap/starter-kit@3.27.1': dependencies: - '@tiptap/core': 3.26.1(@tiptap/pm@3.26.1) - '@tiptap/extension-blockquote': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-bold': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-bullet-list': 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-code': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-code-block': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/extension-document': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-dropcursor': 3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-gapcursor': 3.26.1(@tiptap/extensions@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-hard-break': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-heading': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-horizontal-rule': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/extension-italic': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-link': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/extension-list': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/extension-list-item': 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-list-keymap': 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-ordered-list': 3.26.1(@tiptap/extension-list@3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1)) - '@tiptap/extension-paragraph': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-strike': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-text': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extension-underline': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1)) - '@tiptap/extensions': 3.26.1(@tiptap/core@3.26.1(@tiptap/pm@3.26.1))(@tiptap/pm@3.26.1) - '@tiptap/pm': 3.26.1 + '@tiptap/core': 3.27.1(@tiptap/pm@3.27.1) + '@tiptap/extension-blockquote': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-bold': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-bullet-list': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-code': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-code-block': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-document': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-dropcursor': 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-gapcursor': 3.27.1(@tiptap/extensions@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-hard-break': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-heading': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-horizontal-rule': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-italic': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-link': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/extension-list-item': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-list-keymap': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-ordered-list': 3.27.1(@tiptap/extension-list@3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1)) + '@tiptap/extension-paragraph': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-strike': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-text': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extension-underline': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1)) + '@tiptap/extensions': 3.27.1(@tiptap/core@3.27.1(@tiptap/pm@3.27.1))(@tiptap/pm@3.27.1) + '@tiptap/pm': 3.27.1 '@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3)': dependencies: '@trpc/server': 11.17.0(typescript@6.0.3) typescript: 6.0.3 - '@trpc/next@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/react-query@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(react@19.2.7)(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)': + '@trpc/next@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/react-query@11.17.0(@tanstack/react-query@5.101.0(react@19.2.7))(@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(react@19.2.7)(typescript@6.0.3))(@trpc/server@11.17.0(typescript@6.0.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@6.0.3)': dependencies: '@trpc/client': 11.17.0(@trpc/server@11.17.0(typescript@6.0.3))(typescript@6.0.3) '@trpc/server': 11.17.0(typescript@6.0.3) - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) typescript: 6.0.3 @@ -21233,7 +21307,7 @@ snapshots: '@types/pg@8.20.0': dependencies: '@types/node': 24.13.2 - pg-protocol: 1.14.0 + pg-protocol: 1.15.0 pg-types: 2.2.0 '@types/prismjs@1.26.6': {} @@ -21379,22 +21453,27 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@videojs/http-streaming@3.17.4(video.js@8.23.7)': + '@videojs/http-streaming@3.17.5(video.js@8.23.9)': dependencies: '@babel/runtime': 7.29.7 - '@videojs/vhs-utils': 4.1.1 + '@videojs/vhs-utils': 4.1.2 aes-decrypter: 4.0.2 global: 4.4.0 m3u8-parser: 7.2.0 - mpd-parser: 1.3.1 + mpd-parser: 1.4.0 mux.js: 7.1.0 - video.js: 8.23.7 + video.js: 8.23.9 '@videojs/vhs-utils@4.1.1': dependencies: '@babel/runtime': 7.29.7 global: 4.4.0 + '@videojs/vhs-utils@4.1.2': + dependencies: + '@babel/runtime': 7.29.7 + global: 4.4.0 + '@videojs/xhr@2.7.0': dependencies: '@babel/runtime': 7.29.7 @@ -21408,10 +21487,10 @@ snapshots: optionalDependencies: babel-plugin-react-compiler: 1.0.0 - '@vitest/coverage-v8@4.1.8(vitest@4.1.8)': + '@vitest/coverage-v8@4.1.9(vitest@4.1.9)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.9 ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -21420,58 +21499,58 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - '@vitest/expect@4.1.8': + '@vitest/expect@4.1.9': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.2 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.8(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.9(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.8 + '@vitest/spy': 4.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.14.6(@types/node@24.13.2)(typescript@6.0.3) vite: 8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) - '@vitest/pretty-format@4.1.8': + '@vitest/pretty-format@4.1.9': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.8': + '@vitest/runner@4.1.9': dependencies: - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.9 pathe: 2.0.3 - '@vitest/snapshot@4.1.8': + '@vitest/snapshot@4.1.9': dependencies: - '@vitest/pretty-format': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/pretty-format': 4.1.9 + '@vitest/utils': 4.1.9 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.8': {} + '@vitest/spy@4.1.9': {} - '@vitest/ui@4.1.8(vitest@4.1.8)': + '@vitest/ui@4.1.9(vitest@4.1.9)': dependencies: - '@vitest/utils': 4.1.8 + '@vitest/utils': 4.1.9 fflate: 0.8.2 flatted: 3.4.2 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - '@vitest/utils@4.1.8': + '@vitest/utils@4.1.9': dependencies: - '@vitest/pretty-format': 4.1.8 + '@vitest/pretty-format': 4.1.9 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -21810,17 +21889,27 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - archiver@8.0.0: + anynum@1.0.1: {} + + archiver-utils@5.0.2: dependencies: - async: 3.2.6 - buffer-crc32: 1.0.0 - is-stream: 4.0.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 lazystream: 1.0.1 + lodash: 4.18.1 normalize-path: 3.0.0 readable-stream: 4.5.2 - readdir-glob: 3.0.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.5.2 + readdir-glob: 1.1.3 tar-stream: 3.1.7 - zip-stream: 7.0.5 + zip-stream: 6.0.1 arg@5.0.2: {} @@ -21959,6 +22048,8 @@ snapshots: bail@2.0.2: {} + balanced-match@1.0.2: {} + balanced-match@4.0.2: dependencies: jackspeak: 4.2.3 @@ -22009,10 +22100,10 @@ snapshots: before-after-hook@4.0.0: {} - better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)): + better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)): dependencies: '@better-auth/core': 1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) - '@better-auth/drizzle-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1)) + '@better-auth/drizzle-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1)) '@better-auth/kysely-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(kysely@0.29.2) '@better-auth/memory-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1) '@better-auth/mongo-adapter': 1.6.15(@better-auth/core@1.6.15(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1) @@ -22031,13 +22122,13 @@ snapshots: optionalDependencies: better-sqlite3: 12.10.0 drizzle-kit: 0.31.10 - drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) mysql2: 3.22.5(@types/node@24.13.2) - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) - pg: 8.21.0 + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + pg: 8.22.0 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - vitest: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.9(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) vue: 3.5.35(typescript@6.0.3) transitivePeerDependencies: - '@cloudflare/workers-types' @@ -22141,6 +22232,10 @@ snapshots: widest-line: 4.0.1 wrap-ansi: 8.1.0 + brace-expansion@2.1.1: + dependencies: + balanced-match: 1.0.2 + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.2 @@ -22452,11 +22547,11 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 - compress-commons@7.0.1: + compress-commons@6.0.2: dependencies: crc-32: 1.2.2 - crc32-stream: 7.0.1 - is-stream: 4.0.1 + crc32-stream: 6.0.0 + is-stream: 2.0.1 normalize-path: 3.0.0 readable-stream: 4.5.2 @@ -22620,7 +22715,7 @@ snapshots: crc-32@1.2.2: {} - crc32-stream@7.0.1: + crc32-stream@6.0.0: dependencies: crc-32: 1.2.2 readable-stream: 4.5.2 @@ -23180,6 +23275,10 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dompurify@3.4.11: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@2.8.0: dependencies: dom-serializer: 1.4.1 @@ -23227,7 +23326,7 @@ snapshots: esbuild: 0.25.12 tsx: 4.21.0 - drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1): + drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1): optionalDependencies: '@libsql/client-wasm': 0.14.0 '@opentelemetry/api': 1.9.0 @@ -23237,12 +23336,12 @@ snapshots: gel: 2.0.0 kysely: 0.29.2 mysql2: 3.22.5(@types/node@24.13.2) - pg: 8.21.0 + pg: 8.22.0 sql.js: 1.14.1 - drizzle-zod@0.8.3(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(zod@4.4.3): + drizzle-zod@0.8.3(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(zod@4.4.3): dependencies: - drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1) + drizzle-orm: 0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1) zod: 4.4.3 dunder-proto@1.0.1: @@ -23719,12 +23818,13 @@ snapshots: path-expression-matcher: 1.5.0 xml-naming: 0.1.0 - fast-xml-parser@5.8.0: + fast-xml-parser@5.9.3: dependencies: - '@nodable/entities': 2.1.0 + '@nodable/entities': 2.2.0 fast-xml-builder: 1.2.0 + is-unsafe: 1.0.1 path-expression-matcher: 1.5.0 - strnum: 2.3.0 + strnum: 2.4.1 xml-naming: 0.1.0 fastify@5.8.5: @@ -23859,6 +23959,11 @@ snapshots: follow-redirects@1.16.0: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + form-data-encoder@2.1.4: {} form-data@4.0.6: @@ -23991,6 +24096,15 @@ snapshots: glob-to-regexp@0.4.1: {} + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -24732,6 +24846,8 @@ snapshots: is-unicode-supported@2.1.0: {} + is-unsafe@1.0.1: {} + is-what@5.5.0: {} is-wsl@2.2.0: @@ -24755,9 +24871,9 @@ snapshots: isobject@3.0.1: {} - isomorphic-dompurify@3.17.0(@noble/hashes@2.0.1): + isomorphic-dompurify@3.18.0(@noble/hashes@2.0.1): dependencies: - dompurify: 3.4.10 + dompurify: 3.4.11 jsdom: 29.1.1(@noble/hashes@2.0.1) transitivePeerDependencies: - '@noble/hashes' @@ -24788,6 +24904,12 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jackspeak@4.2.3: dependencies: '@isaacs/cliui': 9.0.0 @@ -25134,7 +25256,7 @@ snapshots: lru.min@1.1.4: {} - lucide-react@1.18.0(react@19.2.7): + lucide-react@1.21.0(react@19.2.7): dependencies: react: 19.2.7 @@ -25158,19 +25280,19 @@ snapshots: dependencies: semver: 7.7.4 - mantine-datatable@9.3.0(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + mantine-datatable@9.3.1(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(clsx@2.1.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) clsx: 2.1.1 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - mantine-react-table-open@9.0.3(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + mantine-react-table-open@9.0.3(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/dates@9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(@tabler/icons-react@3.44.0(react@19.2.7))(clsx@2.1.1)(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - '@mantine/core': 9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/dates': 9.3.1(@mantine/core@9.3.1(@mantine/hooks@9.3.1(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.1(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@mantine/hooks': 9.3.1(react@19.2.7) + '@mantine/core': 9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/dates': 9.3.2(@mantine/core@9.3.2(@mantine/hooks@9.3.2(react@19.2.7))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@mantine/hooks@9.3.2(react@19.2.7))(dayjs@1.11.21)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@mantine/hooks': 9.3.2(react@19.2.7) '@tabler/icons-react': 3.44.0(react@19.2.7) '@tanstack/match-sorter-utils': 8.19.4 '@tanstack/react-table': 8.20.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -25203,23 +25325,23 @@ snapshots: math-intrinsics@1.1.0: {} - mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)): + mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)): dependencies: '@modelcontextprotocol/sdk': 1.26.0(zod@4.4.3) chalk: 5.6.2 commander: 11.1.0 redis: 4.7.1 optionalDependencies: - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) - mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)): + mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)): dependencies: '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) chalk: 5.6.2 commander: 11.1.0 redis: 4.7.1 optionalDependencies: - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) mdast-util-directive@3.1.0: dependencies: @@ -25832,6 +25954,14 @@ snapshots: dependencies: brace-expansion: 5.0.6 + minimatch@5.1.9: + dependencies: + brace-expansion: 5.0.6 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.1 + minimist@1.2.8: {} minipass@7.1.3: {} @@ -25840,10 +25970,10 @@ snapshots: mkdirp@3.0.1: {} - mpd-parser@1.3.1: + mpd-parser@1.4.0: dependencies: '@babel/runtime': 7.29.7 - '@videojs/vhs-utils': 4.1.1 + '@videojs/vhs-utils': 4.1.2 '@xmldom/xmldom': 0.8.10 global: 4.4.0 @@ -25923,6 +26053,8 @@ snapshots: nanoid@5.1.11: {} + nanoid@5.1.15: {} + nanostores@1.3.0: {} napi-build-utils@1.0.2: {} @@ -25939,22 +26071,22 @@ snapshots: neverpanic@0.0.8: {} - next-auth@5.0.0-beta.31(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7): + next-auth@5.0.0-beta.31(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7): dependencies: '@auth/core': 0.41.2 - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) react: 19.2.7 next-intl-swc-plugin-extractor@4.13.0: {} - next-intl@4.13.0(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)(typescript@6.0.3): + next-intl@4.13.0(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(react@19.2.7)(typescript@6.0.3): dependencies: '@formatjs/intl-localematcher': 0.8.1 '@parcel/watcher': 2.4.1 '@swc/core': 1.15.3(@swc/helpers@0.5.15) icu-minify: 4.13.0 negotiator: 1.0.0 - next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0) next-intl-swc-plugin-extractor: 4.13.0 po-parser: 2.1.1 react: 19.2.7 @@ -25964,7 +26096,7 @@ snapshots: transitivePeerDependencies: - '@swc/helpers' - next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0): + next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0): dependencies: '@next/env': 16.2.9 '@swc/helpers': 0.5.15 @@ -25984,7 +26116,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 16.2.9 '@next/swc-win32-x64-msvc': 16.2.9 '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.60.0 + '@playwright/test': 1.61.0 babel-plugin-react-compiler: 1.0.0 sass: 1.101.0 sharp: 0.34.5 @@ -26168,51 +26300,51 @@ snapshots: outvariant@1.4.3: optional: true - oxfmt@0.54.0: + oxfmt@0.55.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.54.0 - '@oxfmt/binding-android-arm64': 0.54.0 - '@oxfmt/binding-darwin-arm64': 0.54.0 - '@oxfmt/binding-darwin-x64': 0.54.0 - '@oxfmt/binding-freebsd-x64': 0.54.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.54.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.54.0 - '@oxfmt/binding-linux-arm64-gnu': 0.54.0 - '@oxfmt/binding-linux-arm64-musl': 0.54.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.54.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.54.0 - '@oxfmt/binding-linux-riscv64-musl': 0.54.0 - '@oxfmt/binding-linux-s390x-gnu': 0.54.0 - '@oxfmt/binding-linux-x64-gnu': 0.54.0 - '@oxfmt/binding-linux-x64-musl': 0.54.0 - '@oxfmt/binding-openharmony-arm64': 0.54.0 - '@oxfmt/binding-win32-arm64-msvc': 0.54.0 - '@oxfmt/binding-win32-ia32-msvc': 0.54.0 - '@oxfmt/binding-win32-x64-msvc': 0.54.0 + '@oxfmt/binding-android-arm-eabi': 0.55.0 + '@oxfmt/binding-android-arm64': 0.55.0 + '@oxfmt/binding-darwin-arm64': 0.55.0 + '@oxfmt/binding-darwin-x64': 0.55.0 + '@oxfmt/binding-freebsd-x64': 0.55.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.55.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.55.0 + '@oxfmt/binding-linux-arm64-gnu': 0.55.0 + '@oxfmt/binding-linux-arm64-musl': 0.55.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.55.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.55.0 + '@oxfmt/binding-linux-riscv64-musl': 0.55.0 + '@oxfmt/binding-linux-s390x-gnu': 0.55.0 + '@oxfmt/binding-linux-x64-gnu': 0.55.0 + '@oxfmt/binding-linux-x64-musl': 0.55.0 + '@oxfmt/binding-openharmony-arm64': 0.55.0 + '@oxfmt/binding-win32-arm64-msvc': 0.55.0 + '@oxfmt/binding-win32-ia32-msvc': 0.55.0 + '@oxfmt/binding-win32-x64-msvc': 0.55.0 - oxlint@1.69.0: + oxlint@1.70.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.69.0 - '@oxlint/binding-android-arm64': 1.69.0 - '@oxlint/binding-darwin-arm64': 1.69.0 - '@oxlint/binding-darwin-x64': 1.69.0 - '@oxlint/binding-freebsd-x64': 1.69.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.69.0 - '@oxlint/binding-linux-arm-musleabihf': 1.69.0 - '@oxlint/binding-linux-arm64-gnu': 1.69.0 - '@oxlint/binding-linux-arm64-musl': 1.69.0 - '@oxlint/binding-linux-ppc64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-gnu': 1.69.0 - '@oxlint/binding-linux-riscv64-musl': 1.69.0 - '@oxlint/binding-linux-s390x-gnu': 1.69.0 - '@oxlint/binding-linux-x64-gnu': 1.69.0 - '@oxlint/binding-linux-x64-musl': 1.69.0 - '@oxlint/binding-openharmony-arm64': 1.69.0 - '@oxlint/binding-win32-arm64-msvc': 1.69.0 - '@oxlint/binding-win32-ia32-msvc': 1.69.0 - '@oxlint/binding-win32-x64-msvc': 1.69.0 + '@oxlint/binding-android-arm-eabi': 1.70.0 + '@oxlint/binding-android-arm64': 1.70.0 + '@oxlint/binding-darwin-arm64': 1.70.0 + '@oxlint/binding-darwin-x64': 1.70.0 + '@oxlint/binding-freebsd-x64': 1.70.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.70.0 + '@oxlint/binding-linux-arm-musleabihf': 1.70.0 + '@oxlint/binding-linux-arm64-gnu': 1.70.0 + '@oxlint/binding-linux-arm64-musl': 1.70.0 + '@oxlint/binding-linux-ppc64-gnu': 1.70.0 + '@oxlint/binding-linux-riscv64-gnu': 1.70.0 + '@oxlint/binding-linux-riscv64-musl': 1.70.0 + '@oxlint/binding-linux-s390x-gnu': 1.70.0 + '@oxlint/binding-linux-x64-gnu': 1.70.0 + '@oxlint/binding-linux-x64-musl': 1.70.0 + '@oxlint/binding-openharmony-arm64': 1.70.0 + '@oxlint/binding-win32-arm64-msvc': 1.70.0 + '@oxlint/binding-win32-ia32-msvc': 1.70.0 + '@oxlint/binding-win32-x64-msvc': 1.70.0 p-cancelable@3.0.0: {} @@ -26267,6 +26399,8 @@ snapshots: p-try@1.0.0: {} + package-json-from-dist@1.0.1: {} + package-json@8.1.1: dependencies: got: 12.6.1 @@ -26375,6 +26509,11 @@ snapshots: dependencies: path-root-regex: 0.1.2 + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + path-scurry@2.0.2: dependencies: lru-cache: 11.3.5 @@ -26400,15 +26539,15 @@ snapshots: pg-cloudflare@1.4.0: optional: true - pg-connection-string@2.13.0: {} + pg-connection-string@2.14.0: {} pg-int8@1.0.1: {} - pg-pool@3.14.0(pg@8.21.0): + pg-pool@3.14.0(pg@8.22.0): dependencies: - pg: 8.21.0 + pg: 8.22.0 - pg-protocol@1.14.0: {} + pg-protocol@1.15.0: {} pg-types@2.2.0: dependencies: @@ -26418,11 +26557,11 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.21.0: + pg@8.22.0: dependencies: - pg-connection-string: 2.13.0 - pg-pool: 3.14.0(pg@8.21.0) - pg-protocol: 1.14.0 + pg-connection-string: 2.14.0 + pg-pool: 3.14.0(pg@8.22.0) + pg-protocol: 1.15.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -26486,11 +26625,11 @@ snapshots: pvutils: 1.1.5 tslib: 2.8.1 - playwright-core@1.60.0: {} + playwright-core@1.61.0: {} - playwright@1.60.0: + playwright@1.61.0: dependencies: - playwright-core: 1.60.0 + playwright-core: 1.61.0 optionalDependencies: fsevents: 2.3.2 @@ -26990,10 +27129,10 @@ snapshots: posthog-docusaurus@2.0.5: {} - posthog-js@1.386.6: + posthog-js@1.391.2: dependencies: - '@posthog/core': 1.32.3 - '@posthog/types': 1.386.3 + '@posthog/core': 1.35.3 + '@posthog/types': 1.390.2 core-js: 3.49.0 dompurify: 3.4.10 fflate: 0.4.8 @@ -27243,7 +27382,7 @@ snapshots: aria-hidden: 1.2.6 defu: 6.1.7 fast-deep-equal: 3.1.3 - nanoid: 5.1.11 + nanoid: 5.1.15 vue: 3.5.35(typescript@6.0.3) transitivePeerDependencies: - '@vue/composition-api' @@ -27493,9 +27632,9 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 - readdir-glob@3.0.0: + readdir-glob@1.1.3: dependencies: - minimatch: 10.2.5 + minimatch: 5.1.9 readdirp@3.6.0: dependencies: @@ -28399,7 +28538,9 @@ snapshots: strip-json-comments@3.1.1: {} - strnum@2.3.0: {} + strnum@2.4.1: + dependencies: + anynum: 1.0.1 style-mod@4.1.3: {} @@ -28588,11 +28729,11 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - testcontainers@12.0.2: + testcontainers@12.0.3: dependencies: '@balena/dockerignore': 1.0.2 '@types/dockerode': 4.0.1 - archiver: 8.0.0 + archiver: 7.0.1 async-lock: 1.4.1 byline: 5.0.0 debug: 4.4.3 @@ -28642,7 +28783,7 @@ snapshots: dependencies: convert-hrtime: 5.0.0 - timezones-ical-library@2.2.0: {} + timezones-ical-library@2.2.1: {} tiny-invariant@1.3.3: {} @@ -28717,23 +28858,23 @@ snapshots: trough@2.2.0: {} - trpc-to-mcp@1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3): + trpc-to-mcp@1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3): dependencies: '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) '@trpc/server': 11.17.0(typescript@6.0.3) - better-auth: 1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)) - mcp-handler: 1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) + better-auth: 1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)) + mcp-handler: 1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) zod: 4.4.3 transitivePeerDependencies: - '@cfworker/json-schema' - supports-color - trpc-to-mcp@1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3): + trpc-to-mcp@1.3.2(@trpc/server@11.17.0(typescript@6.0.3))(better-auth@1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)))(mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)))(zod@4.4.3): dependencies: '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) '@trpc/server': 11.17.0(typescript@6.0.3) - better-auth: 1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.21.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8)(vue@3.5.35(typescript@6.0.3)) - mcp-handler: 1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) + better-auth: 1.6.15(@opentelemetry/api@1.9.0)(better-sqlite3@12.10.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@libsql/client-wasm@0.14.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.20.0)(better-sqlite3@12.10.0)(gel@2.0.0)(kysely@0.29.2)(mysql2@3.22.5(@types/node@24.13.2))(pg@8.22.0)(sql.js@1.14.1))(mysql2@3.22.5(@types/node@24.13.2))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0))(pg@8.22.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.9)(vue@3.5.35(typescript@6.0.3)) + mcp-handler: 1.1.0(@modelcontextprotocol/sdk@1.26.0(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.0)(@playwright/test@1.61.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.101.0)) zod: 4.4.3 transitivePeerDependencies: - '@cfworker/json-schema' @@ -29091,25 +29232,25 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - video.js@8.23.7: + video.js@8.23.9: dependencies: '@babel/runtime': 7.29.7 - '@videojs/http-streaming': 3.17.4(video.js@8.23.7) - '@videojs/vhs-utils': 4.1.1 + '@videojs/http-streaming': 3.17.5(video.js@8.23.9) + '@videojs/vhs-utils': 4.1.2 '@videojs/xhr': 2.7.0 aes-decrypter: 4.0.2 global: 4.4.0 m3u8-parser: 7.2.0 - mpd-parser: 1.3.1 + mpd-parser: 1.4.0 mux.js: 7.1.0 - videojs-contrib-quality-levels: 4.1.0(video.js@8.23.7) + videojs-contrib-quality-levels: 4.1.0(video.js@8.23.9) videojs-font: 4.2.0 videojs-vtt.js: 0.15.5 - videojs-contrib-quality-levels@4.1.0(video.js@8.23.7): + videojs-contrib-quality-levels@4.1.0(video.js@8.23.9): dependencies: global: 4.4.0 - video.js: 8.23.7 + video.js: 8.23.9 videojs-font@4.2.0: {} @@ -29145,15 +29286,15 @@ snapshots: tsx: 4.21.0 yaml: 2.9.0 - vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(@vitest/ui@4.1.8)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)): + vitest@4.1.9(@opentelemetry/api@1.9.0)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(jsdom@29.1.1(@noble/hashes@2.0.1))(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 + '@vitest/expect': 4.1.9 + '@vitest/mocker': 4.1.9(msw@2.14.6(@types/node@24.13.2)(typescript@6.0.3))(vite@8.0.16(@types/node@24.13.2)(esbuild@0.28.0)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.0(postcss@8.5.15))(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.9 + '@vitest/runner': 4.1.9 + '@vitest/snapshot': 4.1.9 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -29170,8 +29311,8 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.13.2 - '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) - '@vitest/ui': 4.1.8(vitest@4.1.8) + '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) + '@vitest/ui': 4.1.9(vitest@4.1.9) jsdom: 29.1.1(@noble/hashes@2.0.1) transitivePeerDependencies: - msw @@ -29621,10 +29762,10 @@ snapshots: yoctocolors@2.1.1: {} - zip-stream@7.0.5: + zip-stream@6.0.1: dependencies: - compress-commons: 7.0.1 - normalize-path: 3.0.0 + archiver-utils: 5.0.2 + compress-commons: 6.0.2 readable-stream: 4.5.2 zod-form-data@3.0.2(zod@4.4.3): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7f4e13c05..24ff4891f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,7 +6,7 @@ catalog: "@auth/core": ^0.41.2 "@auth/drizzle-adapter": ^1.11.2 "@ctrl/deluge": ^8.0.0 - "@ctrl/qbittorrent": ^9.12.2 + "@ctrl/qbittorrent": ^9.14.0 "@ctrl/transmission": ^7.4.0 "@dnd-kit/core": ^6.3.1 "@dnd-kit/modifiers": ^9.0.0 @@ -14,7 +14,7 @@ catalog: "@dnd-kit/utilities": ^3.2.2 "@drizzle-team/brocli": ^0.12.0 "@extractus/feed-extractor": 7.2.1 - '@gfazioli/mantine-onboarding-tour': ^4.0.4 + '@gfazioli/mantine-onboarding-tour': ^4.0.5 "@gitbeaker/rest": ^43.8.0 "@homarr/gridstack": ^1.12.0 "@homarr/node-unifi": ^2.6.0 @@ -22,21 +22,21 @@ catalog: "@jellyfin/sdk": ^0.13.0 "@kubernetes/client-node": ^1.4.0 "@modelcontextprotocol/sdk": 1.29.0 - "@mantine/charts": ^9.3.1 - "@mantine/colors-generator": ^9.3.1 - "@mantine/core": ^9.3.1 - "@mantine/dates": ^9.3.1 - "@mantine/dropzone": ^9.3.1 - "@mantine/form": ^9.3.1 - "@mantine/hooks": ^9.3.1 - "@mantine/modals": ^9.3.1 - "@mantine/notifications": ^9.3.1 - "@mantine/spotlight": ^9.3.1 - "@mantine/tiptap": ^9.3.1 + "@mantine/charts": ^9.3.2 + "@mantine/colors-generator": ^9.3.2 + "@mantine/core": ^9.3.2 + "@mantine/dates": ^9.3.2 + "@mantine/dropzone": ^9.3.2 + "@mantine/form": ^9.3.2 + "@mantine/hooks": ^9.3.2 + "@mantine/modals": ^9.3.2 + "@mantine/notifications": ^9.3.2 + "@mantine/spotlight": ^9.3.2 + "@mantine/tiptap": ^9.3.2 "@next/eslint-plugin-next": 16.2.9 "@octokit/auth-app": ^8.2.0 "@paralleldrive/cuid2": ^3.3.0 - "@playwright/test": ^1.60.0 + "@playwright/test": ^1.61.0 "@semantic-release/changelog": ^6.0.3 "@semantic-release/commit-analyzer": ^13.0.1 "@semantic-release/git": ^10.0.1 @@ -49,25 +49,25 @@ catalog: "@tanstack/react-query": ^5.101.0 "@tanstack/react-query-devtools": ^5.101.0 "@tanstack/react-query-next-experimental": ^5.101.0 - "@testcontainers/mysql": ^12.0.2 - "@testcontainers/postgresql": ^12.0.2 - "@testcontainers/redis": ^12.0.2 - "@tiptap/extension-color": 3.26.1 - "@tiptap/extension-highlight": 3.26.1 - "@tiptap/extension-image": 3.26.1 - "@tiptap/extension-link": ^3.26.1 - "@tiptap/extension-placeholder": ^3.26.1 - "@tiptap/extension-table": 3.26.1 - "@tiptap/extension-table-cell": 3.26.1 - "@tiptap/extension-table-header": 3.26.1 - "@tiptap/extension-table-row": 3.26.1 - "@tiptap/extension-task-item": 3.26.1 - "@tiptap/extension-task-list": 3.26.1 - "@tiptap/extension-text-align": 3.26.1 - "@tiptap/extension-text-style": 3.26.1 - "@tiptap/extension-underline": 3.26.1 - "@tiptap/react": ^3.26.1 - "@tiptap/starter-kit": ^3.26.1 + "@testcontainers/mysql": ^12.0.3 + "@testcontainers/postgresql": ^12.0.3 + "@testcontainers/redis": ^12.0.3 + "@tiptap/extension-color": 3.27.1 + "@tiptap/extension-highlight": 3.27.1 + "@tiptap/extension-image": 3.27.1 + "@tiptap/extension-link": ^3.27.1 + "@tiptap/extension-placeholder": ^3.27.1 + "@tiptap/extension-table": 3.27.1 + "@tiptap/extension-table-cell": 3.27.1 + "@tiptap/extension-table-header": 3.27.1 + "@tiptap/extension-table-row": 3.27.1 + "@tiptap/extension-task-item": 3.27.1 + "@tiptap/extension-task-list": 3.27.1 + "@tiptap/extension-text-align": 3.27.1 + "@tiptap/extension-text-style": 3.27.1 + "@tiptap/extension-underline": 3.27.1 + "@tiptap/react": ^3.27.1 + "@tiptap/starter-kit": ^3.27.1 "@trpc/client": ^11.17.0 "@trpc/next": ^11.17.0 "@trpc/react-query": ^11.17.0 @@ -88,15 +88,15 @@ catalog: "@types/prismjs": ^1.26.6 "@types/react": 19.2.17 "@types/react-dom": 19.2.3 - "@scalar/api-reference-react": ^0.9.46 + "@scalar/api-reference-react": ^0.9.47 "@types/video.js": ^7.3.58 "@types/ws": ^8.18.1 "@types/xml2js": ^0.4.14 - posthog-js: ^1.255.0 - posthog-node: ^4.17.0 + posthog-js: ^1.391.2 + posthog-node: ^4.18.0 "@vitejs/plugin-react": ^6.0.2 - "@vitest/coverage-v8": ^4.1.8 - "@vitest/ui": ^4.1.8 + "@vitest/coverage-v8": ^4.1.9 + "@vitest/ui": ^4.1.9 "@xterm/addon-canvas": ^0.7.0 "@xterm/addon-fit": 0.11.0 "@xterm/xterm": ^6.0.0 @@ -125,22 +125,22 @@ catalog: drizzle-orm: ^0.45.2 drizzle-zod: ^0.8.3 esbuild: ^0.28.0 - fast-xml-parser: ^5.8.0 + fast-xml-parser: ^5.9.3 fastify: ^5.8.5 flag-icons: ^7.5.0 glob: ^13.0.6 ical.js: ^2.2.1 ioredis: 5.11.1 - isomorphic-dompurify: ^3.17.0 + isomorphic-dompurify: ^3.18.0 jotai: ^2.20.1 jsdom: ^29.1.1 json5: ^2.2.3 jsonpath-plus: ^10.4.0 ldapts: 8.1.8 lodash.clonedeep: ^4.5.0 - lucide-react: ^1.18.0 - "mantine-contextmenu": ^9.3.0 - mantine-datatable: ^9.3.0 + lucide-react: ^1.21.0 + "mantine-contextmenu": ^9.3.1 + mantine-datatable: ^9.3.1 mantine-react-table: npm:mantine-react-table-open@9.0.3 mcp-handler: ^1.1.0 maria2: ^0.4.1 @@ -150,9 +150,9 @@ catalog: next-intl: 4.13.0 node-loader: ^2.1.0 octokit: ^5.0.5 - oxfmt: ^0.54.0 - oxlint: ^1.69.0 - pg: ^8.21.0 + oxfmt: ^0.55.0 + oxlint: ^1.70.0 + pg: ^8.22.0 postcss-preset-mantine: ^1.18.0 prismjs: ^1.30.0 proxmox-api: 1.1.1 @@ -169,8 +169,8 @@ catalog: semver-parser: ^4.2.1 superjson: 2.2.6 svgson: ^5.3.1 - testcontainers: ^12.0.2 - timezones-ical-library: ^2.2.0 + testcontainers: ^12.0.3 + timezones-ical-library: ^2.2.1 trpc-to-mcp: ^1.3.2 trpc-to-openapi: ^3.3.0 tsdav: ^2.2.2 @@ -180,9 +180,9 @@ catalog: vite: ^8.0.16 undici: 7.27.2 use-deep-compare-effect: ^1.8.1 - video.js: ^8.23.7 + video.js: ^8.23.9 vite-tsconfig-paths: ^6.1.1 - vitest: ^4.1.8 + vitest: ^4.1.9 winston: 3.19.0 ws: ^8.21.0 xml2js: ^0.6.2 @@ -206,18 +206,18 @@ minimumReleaseAgeExclude: overrides: "@babel/helpers@<7.26.10": ">=7.29.7" "@babel/runtime@<7.26.10": ">=7.29.7" - "axios@>=1.0.0 <1.8.2": ">=1.17.0" + "axios@>=1.0.0 <1.8.2": ">=1.18.0" "brace-expansion@>=2.0.0 <=2.0.1": ">=5.0.6" "brace-expansion@>=1.0.0 <=1.1.11": ">=5.0.6" "esbuild@<=0.24.2": ">=0.28.0" "form-data@>=4.0.0 <4.0.4": ">=4.0.6" - "hono@<4.6.5": ">=4.12.25" + "hono@<4.6.5": ">=4.12.26" "linkifyjs@<4.3.2": ">=4.3.3" - "nanoid@>=4.0.0 <5.0.9": ">=5.1.11" + "nanoid@>=4.0.0 <5.0.9": ">=5.1.15" "prismjs@<1.30.0": ">=1.30.0" "proxmox-api>undici": "7.27.1" "react-is": "^19.2.7" - "rollup@>=4.0.0 <4.22.4": ">=4.62.0" + "rollup@>=4.0.0 <4.22.4": ">=4.62.2" "sha.js@<=2.4.11": ">=2.4.12" "tar-fs@>=3.0.0 <3.0.9": ">=3.1.2" "tar-fs@>=2.0.0 <2.1.3": ">=3.1.2" diff --git a/static-data/contributors.json b/static-data/contributors.json index 2137df790..07d22132c 100644 --- a/static-data/contributors.json +++ b/static-data/contributors.json @@ -1 +1 @@ -[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"marektancak0106","avatar_url":"https://avatars.githubusercontent.com/u/25422667?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"beanbag420","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/u/47495914?v=4"},{"login":"bebsworthy","avatar_url":"https://avatars.githubusercontent.com/u/5266759?v=4"},{"login":"catrielmuller","avatar_url":"https://avatars.githubusercontent.com/u/2272323?v=4"},{"login":"Vysp3r","avatar_url":"https://avatars.githubusercontent.com/u/62019735?v=4"},{"login":"DR-Blogs","avatar_url":"https://avatars.githubusercontent.com/u/96393186?v=4"},{"login":"singular0","avatar_url":"https://avatars.githubusercontent.com/u/1925883?v=4"},{"login":"diogovalentte","avatar_url":"https://avatars.githubusercontent.com/u/49578155?v=4"},{"login":"codezninja","avatar_url":"https://avatars.githubusercontent.com/u/4400773?v=4"},{"login":"fabricionaweb","avatar_url":"https://avatars.githubusercontent.com/u/15933?v=4"},{"login":"nyok1912","avatar_url":"https://avatars.githubusercontent.com/u/32163949?v=4"},{"login":"bo3bdo","avatar_url":"https://avatars.githubusercontent.com/u/5271380?v=4"},{"login":"hskrtich","avatar_url":"https://avatars.githubusercontent.com/u/1214484?v=4"},{"login":"ishults","avatar_url":"https://avatars.githubusercontent.com/u/7275442?v=4"},{"login":"jelliuk","avatar_url":"https://avatars.githubusercontent.com/u/4790959?v=4"},{"login":"Moohan","avatar_url":"https://avatars.githubusercontent.com/u/5982260?v=4"},{"login":"tesar-tech","avatar_url":"https://avatars.githubusercontent.com/u/33880579?v=4"},{"login":"jbruell","avatar_url":"https://avatars.githubusercontent.com/u/31685172?v=4"},{"login":"JasonLeeB06","avatar_url":"https://avatars.githubusercontent.com/u/82266978?v=4"},{"login":"jeffersonraimon","avatar_url":"https://avatars.githubusercontent.com/u/80064475?v=4"},{"login":"jo-chemla","avatar_url":"https://avatars.githubusercontent.com/u/16822841?v=4"},{"login":"joser93","avatar_url":"https://avatars.githubusercontent.com/u/6912089?v=4"},{"login":"justijndepover","avatar_url":"https://avatars.githubusercontent.com/u/9008623?v=4"},{"login":"Aandree5","avatar_url":"https://avatars.githubusercontent.com/u/32734153?v=4"},{"login":"mvanhorn","avatar_url":"https://avatars.githubusercontent.com/u/455140?v=4"},{"login":"jackwellerreal","avatar_url":"https://avatars.githubusercontent.com/u/97435840?v=4"},{"login":"afonsojramos","avatar_url":"https://avatars.githubusercontent.com/u/19473034?v=4"},{"login":"Copilot","avatar_url":"https://avatars.githubusercontent.com/in/1143301?v=4"},{"login":"SergioChan","avatar_url":"https://avatars.githubusercontent.com/u/10103766?v=4"},{"login":"toineenzo","avatar_url":"https://avatars.githubusercontent.com/u/4921397?v=4"},{"login":"oben01","avatar_url":"https://avatars.githubusercontent.com/u/22369027?v=4"},{"login":"rezstje","avatar_url":"https://avatars.githubusercontent.com/u/45420315?v=4"},{"login":"castielwaverly","avatar_url":"https://avatars.githubusercontent.com/u/137005689?v=4"},{"login":"xoxyuxu","avatar_url":"https://avatars.githubusercontent.com/u/3543416?v=4"},{"login":"StrandedTurtle","avatar_url":"https://avatars.githubusercontent.com/u/132835255?v=4"},{"login":"MaienM","avatar_url":"https://avatars.githubusercontent.com/u/583129?v=4"},{"login":"kylegrieder","avatar_url":"https://avatars.githubusercontent.com/u/25424229?v=4"},{"login":"HeapReaper","avatar_url":"https://avatars.githubusercontent.com/u/31496522?v=4"},{"login":"lopsch","avatar_url":"https://avatars.githubusercontent.com/u/4073114?v=4"},{"login":"Gilmoursa","avatar_url":"https://avatars.githubusercontent.com/u/10321421?v=4"},{"login":"Bricklou","avatar_url":"https://avatars.githubusercontent.com/u/15181236?v=4"},{"login":"mairas","avatar_url":"https://avatars.githubusercontent.com/u/407010?v=4"},{"login":"itzTheMeow","avatar_url":"https://avatars.githubusercontent.com/u/50887230?v=4"},{"login":"Nerdy-Technician","avatar_url":"https://avatars.githubusercontent.com/u/45691205?v=4"},{"login":"NicolasNewman","avatar_url":"https://avatars.githubusercontent.com/u/16135852?v=4"},{"login":"NikeLaosClericus","avatar_url":"https://avatars.githubusercontent.com/u/39810627?v=4"},{"login":"noahcroghan","avatar_url":"https://avatars.githubusercontent.com/u/27422774?v=4"},{"login":"ohmzi","avatar_url":"https://avatars.githubusercontent.com/u/6551272?v=4"},{"login":"Rhiz3K","avatar_url":"https://avatars.githubusercontent.com/u/33246262?v=4"},{"login":"saschabuehrle","avatar_url":"https://avatars.githubusercontent.com/u/47737812?v=4"},{"login":"CrazyWolf13","avatar_url":"https://avatars.githubusercontent.com/u/96661824?v=4"},{"login":"VIVAAN-DHAWAN","avatar_url":"https://avatars.githubusercontent.com/u/150339722?v=4"},{"login":"generalmat82","avatar_url":"https://avatars.githubusercontent.com/u/110256073?v=4"},{"login":"lthomsen","avatar_url":"https://avatars.githubusercontent.com/u/28560325?v=4"},{"login":"pitschi","avatar_url":"https://avatars.githubusercontent.com/u/6841565?v=4"},{"login":"sharpsalat","avatar_url":"https://avatars.githubusercontent.com/u/15666932?v=4"},{"login":"tech62","avatar_url":"https://avatars.githubusercontent.com/u/16237642?v=4"},{"login":"AartSchinkel","avatar_url":"https://avatars.githubusercontent.com/u/189675191?v=4"},{"login":"m0s4ik","avatar_url":"https://avatars.githubusercontent.com/u/26578395?v=4"},{"login":"ashtonbatty","avatar_url":"https://avatars.githubusercontent.com/u/230635?v=4"},{"login":"Oupsman","avatar_url":"https://avatars.githubusercontent.com/u/11260343?v=4"},{"login":"cethien","avatar_url":"https://avatars.githubusercontent.com/u/60463918?v=4"},{"login":"DZ945brH","avatar_url":"https://avatars.githubusercontent.com/u/42635243?v=4"},{"login":"dgshue","avatar_url":"https://avatars.githubusercontent.com/u/12952156?v=4"},{"login":"d-lindahl","avatar_url":"https://avatars.githubusercontent.com/u/690410?v=4"},{"login":"KartulUdus","avatar_url":"https://avatars.githubusercontent.com/u/23346150?v=4"},{"login":"ieugen","avatar_url":"https://avatars.githubusercontent.com/u/1050920?v=4"},{"login":"faugusto-oliveira","avatar_url":"https://avatars.githubusercontent.com/u/37384074?v=4"},{"login":"frankvHoof93","avatar_url":"https://avatars.githubusercontent.com/u/7346516?v=4"},{"login":"darbyjack","avatar_url":"https://avatars.githubusercontent.com/u/21014720?v=4"},{"login":"febrile42","avatar_url":"https://avatars.githubusercontent.com/u/14597122?v=4"},{"login":"Kaotic3","avatar_url":"https://avatars.githubusercontent.com/u/80522225?v=4"},{"login":"KelianB","avatar_url":"https://avatars.githubusercontent.com/u/11216155?v=4"},{"login":"hotrungnhan","avatar_url":"https://avatars.githubusercontent.com/u/40029631?v=4"},{"login":"leandroscardua","avatar_url":"https://avatars.githubusercontent.com/u/24698541?v=4"}] \ No newline at end of file +[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"marektancak0106","avatar_url":"https://avatars.githubusercontent.com/u/25422667?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"beanbag420","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/u/47495914?v=4"},{"login":"bebsworthy","avatar_url":"https://avatars.githubusercontent.com/u/5266759?v=4"},{"login":"catrielmuller","avatar_url":"https://avatars.githubusercontent.com/u/2272323?v=4"},{"login":"Vysp3r","avatar_url":"https://avatars.githubusercontent.com/u/62019735?v=4"},{"login":"DR-Blogs","avatar_url":"https://avatars.githubusercontent.com/u/96393186?v=4"},{"login":"singular0","avatar_url":"https://avatars.githubusercontent.com/u/1925883?v=4"},{"login":"diogovalentte","avatar_url":"https://avatars.githubusercontent.com/u/49578155?v=4"},{"login":"codezninja","avatar_url":"https://avatars.githubusercontent.com/u/4400773?v=4"},{"login":"fabricionaweb","avatar_url":"https://avatars.githubusercontent.com/u/15933?v=4"},{"login":"nyok1912","avatar_url":"https://avatars.githubusercontent.com/u/32163949?v=4"},{"login":"bo3bdo","avatar_url":"https://avatars.githubusercontent.com/u/5271380?v=4"},{"login":"hskrtich","avatar_url":"https://avatars.githubusercontent.com/u/1214484?v=4"},{"login":"ishults","avatar_url":"https://avatars.githubusercontent.com/u/7275442?v=4"},{"login":"jelliuk","avatar_url":"https://avatars.githubusercontent.com/u/4790959?v=4"},{"login":"Moohan","avatar_url":"https://avatars.githubusercontent.com/u/5982260?v=4"},{"login":"tesar-tech","avatar_url":"https://avatars.githubusercontent.com/u/33880579?v=4"},{"login":"jbruell","avatar_url":"https://avatars.githubusercontent.com/u/31685172?v=4"},{"login":"JasonLeeB06","avatar_url":"https://avatars.githubusercontent.com/u/82266978?v=4"},{"login":"jeffersonraimon","avatar_url":"https://avatars.githubusercontent.com/u/80064475?v=4"},{"login":"jo-chemla","avatar_url":"https://avatars.githubusercontent.com/u/16822841?v=4"},{"login":"joser93","avatar_url":"https://avatars.githubusercontent.com/u/6912089?v=4"},{"login":"justijndepover","avatar_url":"https://avatars.githubusercontent.com/u/9008623?v=4"},{"login":"Aandree5","avatar_url":"https://avatars.githubusercontent.com/u/32734153?v=4"},{"login":"afonsojramos","avatar_url":"https://avatars.githubusercontent.com/u/19473034?v=4"},{"login":"mvanhorn","avatar_url":"https://avatars.githubusercontent.com/u/455140?v=4"},{"login":"jackwellerreal","avatar_url":"https://avatars.githubusercontent.com/u/97435840?v=4"},{"login":"Copilot","avatar_url":"https://avatars.githubusercontent.com/in/1143301?v=4"},{"login":"SergioChan","avatar_url":"https://avatars.githubusercontent.com/u/10103766?v=4"},{"login":"toineenzo","avatar_url":"https://avatars.githubusercontent.com/u/4921397?v=4"},{"login":"oben01","avatar_url":"https://avatars.githubusercontent.com/u/22369027?v=4"},{"login":"rezstje","avatar_url":"https://avatars.githubusercontent.com/u/45420315?v=4"},{"login":"castielwaverly","avatar_url":"https://avatars.githubusercontent.com/u/137005689?v=4"},{"login":"xoxyuxu","avatar_url":"https://avatars.githubusercontent.com/u/3543416?v=4"},{"login":"StrandedTurtle","avatar_url":"https://avatars.githubusercontent.com/u/132835255?v=4"},{"login":"MaienM","avatar_url":"https://avatars.githubusercontent.com/u/583129?v=4"},{"login":"kylegrieder","avatar_url":"https://avatars.githubusercontent.com/u/25424229?v=4"},{"login":"HeapReaper","avatar_url":"https://avatars.githubusercontent.com/u/31496522?v=4"},{"login":"lopsch","avatar_url":"https://avatars.githubusercontent.com/u/4073114?v=4"},{"login":"Gilmoursa","avatar_url":"https://avatars.githubusercontent.com/u/10321421?v=4"},{"login":"Lok3sh-kumar","avatar_url":"https://avatars.githubusercontent.com/u/110459168?v=4"},{"login":"Bricklou","avatar_url":"https://avatars.githubusercontent.com/u/15181236?v=4"},{"login":"mairas","avatar_url":"https://avatars.githubusercontent.com/u/407010?v=4"},{"login":"itzTheMeow","avatar_url":"https://avatars.githubusercontent.com/u/50887230?v=4"},{"login":"Nerdy-Technician","avatar_url":"https://avatars.githubusercontent.com/u/45691205?v=4"},{"login":"NicolasNewman","avatar_url":"https://avatars.githubusercontent.com/u/16135852?v=4"},{"login":"NikeLaosClericus","avatar_url":"https://avatars.githubusercontent.com/u/39810627?v=4"},{"login":"noahcroghan","avatar_url":"https://avatars.githubusercontent.com/u/27422774?v=4"},{"login":"ohmzi","avatar_url":"https://avatars.githubusercontent.com/u/6551272?v=4"},{"login":"Rhiz3K","avatar_url":"https://avatars.githubusercontent.com/u/33246262?v=4"},{"login":"saschabuehrle","avatar_url":"https://avatars.githubusercontent.com/u/47737812?v=4"},{"login":"CrazyWolf13","avatar_url":"https://avatars.githubusercontent.com/u/96661824?v=4"},{"login":"VIVAAN-DHAWAN","avatar_url":"https://avatars.githubusercontent.com/u/150339722?v=4"},{"login":"generalmat82","avatar_url":"https://avatars.githubusercontent.com/u/110256073?v=4"},{"login":"lthomsen","avatar_url":"https://avatars.githubusercontent.com/u/28560325?v=4"},{"login":"pitschi","avatar_url":"https://avatars.githubusercontent.com/u/6841565?v=4"},{"login":"sharpsalat","avatar_url":"https://avatars.githubusercontent.com/u/15666932?v=4"},{"login":"tech62","avatar_url":"https://avatars.githubusercontent.com/u/16237642?v=4"},{"login":"AartSchinkel","avatar_url":"https://avatars.githubusercontent.com/u/189675191?v=4"},{"login":"m0s4ik","avatar_url":"https://avatars.githubusercontent.com/u/26578395?v=4"},{"login":"ashtonbatty","avatar_url":"https://avatars.githubusercontent.com/u/230635?v=4"},{"login":"Oupsman","avatar_url":"https://avatars.githubusercontent.com/u/11260343?v=4"},{"login":"Bergasha","avatar_url":"https://avatars.githubusercontent.com/u/25044200?v=4"},{"login":"cethien","avatar_url":"https://avatars.githubusercontent.com/u/60463918?v=4"},{"login":"DZ945brH","avatar_url":"https://avatars.githubusercontent.com/u/42635243?v=4"},{"login":"dgshue","avatar_url":"https://avatars.githubusercontent.com/u/12952156?v=4"},{"login":"d-lindahl","avatar_url":"https://avatars.githubusercontent.com/u/690410?v=4"},{"login":"KartulUdus","avatar_url":"https://avatars.githubusercontent.com/u/23346150?v=4"},{"login":"ieugen","avatar_url":"https://avatars.githubusercontent.com/u/1050920?v=4"},{"login":"faugusto-oliveira","avatar_url":"https://avatars.githubusercontent.com/u/37384074?v=4"},{"login":"frankvHoof93","avatar_url":"https://avatars.githubusercontent.com/u/7346516?v=4"},{"login":"darbyjack","avatar_url":"https://avatars.githubusercontent.com/u/21014720?v=4"},{"login":"febrile42","avatar_url":"https://avatars.githubusercontent.com/u/14597122?v=4"},{"login":"Kaotic3","avatar_url":"https://avatars.githubusercontent.com/u/80522225?v=4"},{"login":"KelianB","avatar_url":"https://avatars.githubusercontent.com/u/11216155?v=4"},{"login":"hotrungnhan","avatar_url":"https://avatars.githubusercontent.com/u/40029631?v=4"},{"login":"leandroscardua","avatar_url":"https://avatars.githubusercontent.com/u/24698541?v=4"}] \ No newline at end of file diff --git a/static-data/translators.json b/static-data/translators.json index 221b28e9d..4d0b1456d 100644 --- a/static-data/translators.json +++ b/static-data/translators.json @@ -1 +1 @@ -[{"username":"carlchina","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png"},{"username":"zielmann","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png"},{"username":"Thalyn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png"},{"username":"magnushj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png"},{"username":"almontegil","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png"},{"username":"andibing","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg"},{"username":"gronare","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png"},{"username":"SmartPhoneLover","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg"},{"username":"marcelotk_15","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png"},{"username":"S3OD177","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png"},{"username":"marcg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png"},{"username":"BeersTeddy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png"},{"username":"jamesmcmahon0","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg"},{"username":"b1nar10","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/aaa1f083e04c572f953fde4563171e4a.jpeg"},{"username":"vannCN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg"},{"username":"binswm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png"},{"username":"SkewRam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg"},{"username":"raphcatarino","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg"},{"username":"shillos5","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg"},{"username":"wolong98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg"},{"username":"spair0039","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png"},{"username":"MajorMarcin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg"},{"username":"KosmoMoustache","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png"},{"username":"Soochaehwa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png"},{"username":"garryfield","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg"},{"username":"droidenko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg"},{"username":"maathis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg"},{"username":"bukvam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg"},{"username":"gm.cinalli","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg"},{"username":"antoine2tt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png"},{"username":"cretzen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg"},{"username":"ktKongTong","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg"},{"username":"marinkaberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14861042/medium/2d5c4e62613f03082f3e645fa92efd59.jpeg"},{"username":"djismgaming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14934947/medium/f5a8570713c34ab0f7d5405d105e2a9a.jpeg"},{"username":"f1refa11","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14949159/medium/fd2ae63b8eb4462200ba96abf943c1b9.png"},{"username":"jeffersonraimon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057621/medium/6dff469563860e2618bc9d45646d0ab4.png"},{"username":"giop98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057987/medium/b8a4825d3fc39fc662f35ee258db4b2d.jpeg"},{"username":"tomislav.kraljevic","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15118857/medium/e133f1061cc92850b854d05d8faaeafd.png"},{"username":"Walkx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15202182/medium/5c37361ae45aeed487b34582c1f7ca37.png"},{"username":"andrea.rosso","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15246318/medium/11f3f5ef44ec7f55b6f143090e208704_default.png"},{"username":"ajnart","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15270132/medium/a0f107a463c8910ee96bc2fa843a17e3.jpeg"},{"username":"Witchling","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15282238/medium/9e196b6783415b10ca571b7673c2ef33.jpg"},{"username":"guineuu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15292058/medium/22fbb758bda3b7805d50bf21d38f2c20.jpeg"},{"username":"Bulgus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15304568/medium/0e8787e5ceb02ed5c96a514d0068ae87.jpg"},{"username":"Narno","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15314996/medium/a6ba093f24884250a1bf6c6f2ca50f1b_default.png"},{"username":"BySempron","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15315986/medium/e3d22d7b1423c6823a9f36d595ed4bdb.png"},{"username":"jonathan.berglin.work","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15359236/medium/95930b2093db13b76179782f7322c5d5.png"},{"username":"icdmkg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405504/medium/f334d16cde1ac4ffb935b440d03465af.gif"},{"username":"irithys","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405614/medium/3086461c47cce0a0c031925e5f943412.png"},{"username":"JannesV","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419912/medium/a7809eb4b817d7c49b62cf10ae86b950.png"},{"username":"benniblot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419914/medium/8086b1573d31f152ba41949b3a172445.jpeg"},{"username":"pacjo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419916/medium/3cbeddbd7bc01faafb5a3bf47bba915b_default.png"},{"username":"Payou6994","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419934/medium/37c9b9b17dfb578404c1c1ddb73ba7a8.png"},{"username":"fzibi21","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419976/medium/0da688450358e0290a7b7359cc1f7328.png"},{"username":"WowMurdock","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420118/medium/de19576fccb495b6dfe4c4c04a56b834.png"},{"username":"hbooo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420120/medium/6c7c7f8db785061356ebb03d044d3329.jpeg"},{"username":"Manicraft1001","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420178/medium/50ec94563a06a9f74f33bd09f01eed4d.jpg"},{"username":"Void123","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420354/medium/86929d44df92a00f9fe900a985c196df_default.png"},{"username":"R4cc","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15422606/medium/a390979662b84694f59de30bdb732141.jpeg"},{"username":"fabricionaweb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15425808/medium/a9354142e7ae5152c144409d55fda551_default.png"},{"username":"JokeOfDead","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15426890/medium/a383eac9365e9de64fd4ab1d6fd0cb95.jpeg"},{"username":"hkz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15427174/medium/c88acefb0d7306e1f7470e872029fb39_default.png"},{"username":"Steken","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428516/medium/d5aea5653c769c3a523182bdb60d1664.png"},{"username":"flar.anton","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428592/medium/b01fdb365d892e9f811f77fcb50a80a2.jpeg"},{"username":"Bon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15433542/medium/5397da4dfc821f20b6ac14fe0c514e9a.jpeg"},{"username":"bfkadan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434162/medium/4f9a0b43cfe3acaea60124c14ba7f44a.png"},{"username":"BunnySweety","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434662/medium/f0ef200a6a0dcf0e1d0e9ecd4148f560_default.png"},{"username":"HRKings","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15436168/medium/69a31e461d38549f01864e7ef10d642e.png"},{"username":"wiston81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15439078/medium/10f292c8d12a7c21a44b54495fa4a3d8.jpeg"},{"username":"qaz0911","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15440860/medium/3d3e50ee388c72dc4bf7a771761f2d89_default.png"},{"username":"qqyule","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15441462/medium/7a3cdf82710ffb5d8f388bc0bd010665.png"},{"username":"Bims0n","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15445560/medium/603220b603eeb3367e0f0d3fa675247c.jpg"},{"username":"TariqDaCoder","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15446228/medium/50b0f4040112bbd67690b769477398e5_default.png"},{"username":"Anarchon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15449644/medium/e925e1f3e3ffbf0f982391ce263a1a28.jpeg"},{"username":"Ashun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15453020/medium/ccdcf51c73d6aae40751bb30beee1915_default.png"},{"username":"sebekmartin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15454038/medium/bcfb44598cdfd1d7cd4eb35812538962.jpeg"},{"username":"RagnarGraves","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15459882/medium/143d5af850c1154070a218bea124e9cb_default.png"},{"username":"PrtmPhlp","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15462414/medium/b80db55e9de301432dcd1f8c8b24fd49_default.png"},{"username":"DooYoo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15470768/medium/2a18cf4be67094724b508c9e1e698a21_default.png"},{"username":"espentruls","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486092/medium/8e38afc3a4ff669226a0cfd3e420ff3a.jpeg"},{"username":"frisco82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486922/medium/4e1c5d4189b42508e660daa3c1c25b2a.jpeg"},{"username":"lupineDK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15491798/medium/461bd501e8371c062bf29ea171aedd36_default.png"},{"username":"hillaliy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15492732/medium/0bae17b421604892d888e3fc70cf0587.jpeg"},{"username":"MarcOrfilaCarreras","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15501072/medium/ea52b26c3c6f21e4931e38e3ce3f3d6e.png"},{"username":"robertbridda","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15507822/medium/a368c2e30411bb2da9b49290084191f3.png"},{"username":"MKoniuszko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518090/medium/87605434fcc839f6763ab07c50f6d232.jpeg"},{"username":"HeroSizy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518710/medium/4e79c0e98cbeb536dd961e656331b509.png"},{"username":"dwt136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15520022/medium/554422503f2baea43ace85facb4546fb_default.png"},{"username":"asifthewebguy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15526719/medium/b18931dd0c800d725048bd440646198b_default.png"},{"username":"eiloogs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15545537/medium/f290a2f1190983530a9b76b2e858a609.gif"},{"username":"_vytdv","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15547289/medium/60d8644cc8ad6f11a92ccea4a14cd098_default.png"},{"username":"crendasien","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15554645/medium/598ab1d4aaf6b8dccd5ba16be92da7b9.jpeg"},{"username":"edxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15573823/medium/8a565b732a75a77f840dd123cdb30bf4.png"},{"username":"somerlev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15617065/medium/f4b13513e311ec902d90b2f718412c55.jpg"},{"username":"kid1412621","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15643771/medium/dd455e32de652fa88e6fd97598bdffa7.png"},{"username":"suming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15644717/medium/244159dfe10fa03436205506f80c9e25.png"},{"username":"nick.gher","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15647517/medium/5374a2c6fef60a3fbf0edf86b997c351_default.png"},{"username":"DataCat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15650315/medium/ce7c1365adf35c5d490d77500a4607fb_default.png"},{"username":"dizo89","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15658375/medium/0ca745e5017d491fe1b22b0239904de8.jpeg"},{"username":"tee_noodle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674577/medium/804d9cf06f5196026acb6436b809d0da_default.png"},{"username":"Marty88","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674593/medium/492b1509d52bd2809dea768121217125.jpeg"},{"username":"Spillebulle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15677023/medium/20b98bb85062e07afe0e63618f8a5feb.PNG"},{"username":"petitmewen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15685239/medium/15de9b62d2e0bc25013435f1784bbcc1.jpeg"},{"username":"NoProsNoNoobs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15687709/medium/ae8f65fafeb8bcf74dcb8871bbe46461.png"},{"username":"y.gybson","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15690777/medium/b5cb5d2d5768904ff6586c727e3a6c77.jpeg"},{"username":"inside90","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15704947/medium/c1355fcb30dd76f8e39d98d1d49f1c52.png"},{"username":"RJSkudra","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15709853/medium/c3abf2774913dc4e81fb261d36d7668c.png"},{"username":"binge203","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15713937/medium/77c1cfa4314673db80e6881fd9f64668.gif"},{"username":"Mailootje","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15714337/medium/743c3bc4ab1989966a375eeeec83d8b8.jpeg"},{"username":"tim-wiegers","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15719805/medium/08a96f064813350661cd6b20bf3d7d99.png"},{"username":"GkhnG","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15722911/medium/71a027caec489ef6ce82bcf1888329d0_default.png"},{"username":"Zoen-Millo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15760967/medium/9e956f11adc5b34f5636268b5c485dbf.jpg"},{"username":"HooinKyoma","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15792897/medium/9489f0a9b368e0e827ae758b740a2eed.jpeg"},{"username":"wathergeen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15794495/medium/a83b7fc80d180669ebfd6deb3544cfd0.png"},{"username":"MoeToo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15818233/medium/d35cd6953717706eaf20f6c143c62947.png"},{"username":"itodouble","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15836233/medium/e984caea18fb0673bf319fcf28cef649.png"},{"username":"loslocitos","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15847901/medium/fe30d12fd2cf38212f929e13b169f9ec.jpeg"},{"username":"Oversleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15849065/medium/06141f13a6d541d753f3c2f2947b8068_default.png"},{"username":"Beardy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15865139/medium/fca6b9d2b3f52e286d1568f52b83b6a0_default.png"},{"username":"raelyan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15875457/medium/2f4fda1d1aaa5dcc79b328baf3f03151.jpeg"},{"username":"dolphin738","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15913763/medium/ee6fede7b8528ca642329ada80d1cc18.png"},{"username":"brunotco","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15916719/medium/09db45880fc05abc18adb8d932a5ecf9_default.png"},{"username":"LukeIsHereToDevelop","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15924739/medium/3e6cd3940297bb4ba7bb039c93e6f918.png"},{"username":"kennit","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15925879/medium/6b0733ad3c5949b91c55e4d8b03db8a5_default.png"},{"username":"kuunpire","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15950309/medium/8192a4f08f07086828ac9f74ed29a169.jpeg"},{"username":"Sandor-dev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15951759/medium/0216c2da4eb028164ebbecf1c72f6271_default.png"},{"username":"Meierschlumpf","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15953187/medium/23c744faef1ab84fbdc9351a7850aab6.jpeg"},{"username":"harmlesscat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15970733/medium/dd8d0214a0250c932bb518b1b55e45a2_default.png"},{"username":"OrzWTF","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15976121/medium/4c4557cbff7ff7b0503455bc59c020e0.jpeg"},{"username":"tagaishi","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15977271/medium/eade504c83a5a1ff831c80a538fbdb44_default.png"},{"username":"azurite928","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15981895/medium/547ccc459ee123e78b5401c499f1022d.png"},{"username":"Ronner231","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16021342/medium/7734d550df2de5a2fec2ffff33e7024c.jpeg"},{"username":"ugyes","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16034148/medium/ed001e3f470a2dea9a8ce955b18e7bd5.png"},{"username":"rpieja","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16045554/medium/bd55baca2ef8b92502a760cc9ee7c505_default.png"},{"username":"flambyisyou","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16051620/medium/3a3bc0c90f6b95ab4ef74396a0a17beb.png"},{"username":"Topbcy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16077170/medium/d3aed33ea56330338756cfcd89477cfe.jpeg"},{"username":"ai5d02sb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16084674/medium/7c8119fe2a5ca71bb15f636916a42b95_default.png"},{"username":"explosiveparrot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16097722/medium/7762f80fc1da63f5b2eb87de9d640324_default.png"},{"username":"DestroyCom","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16111544/medium/83e3d3ac5c8bfed634cd1a074854db67.png"},{"username":"neotraxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16116966/medium/b30df957873329019a8a90a69f6efe3a.png"},{"username":"gzxpa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16123314/medium/487b05577310a946b0b98bc72c11213b_default.png"},{"username":"TORIK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16124732/medium/de770890e6411860ac06e8cc2dc0abd0_default.png"},{"username":"sergio.pibot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16138114/medium/80db802b2fcd6bbf19ea4c7413367dca.jpeg"},{"username":"karam-ajaj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16139838/medium/7539ab958d3c85d5f67e7849483ea8f7.jpeg"},{"username":"SimonHenz97","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16151520/medium/9b94a85b536688e2d94538c384fd0a76.png"},{"username":"olsson82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16198988/medium/eeaab4cba210c537424d4204754b604e.png"},{"username":"bo3bdo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16222806/medium/8652f3beacb6098dde5a4cd0a29fe80d.jpeg"},{"username":"AngryPlayer04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245192/medium/342715274f4dc31fd4132cdae9126188.jpeg"},{"username":"ehatamm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245884/medium/979d5e5526fe545be9bf46db481f7182.jpeg"},{"username":"Balionelis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16246058/medium/986d62ba363594c517d966fe9178dcbb.png"},{"username":"kwargs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16248816/medium/19ce11f04bf1ae2637e0483399c675f9_default.png"},{"username":"lucicu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16273892/medium/3b09e8f3bead221ef98d6a45a16851dc_default.png"},{"username":"Michael5564445","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16357688/medium/9d9026a8bf3eaccb0417da240932ebf7.png"},{"username":"Netscream","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16359198/medium/694e0c8572dc8a47e6d63da31ec5b992.png"},{"username":"belicstefan04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16368142/medium/4742dcfd7bf7ad7e33e37ac44fba7e0f.png"},{"username":"Hamad2066","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16371478/medium/f37bbc7685b6757defdbd1494236af61.jpeg"},{"username":"3ct0pl4sm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16399616/medium/ce796d1c40163975624c0a483e56374f.png"},{"username":"sanchez.marcell626","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16433865/medium/3ddde1314764cc2205ffdcd1ae719a91.png"},{"username":"Minoctis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16490079/medium/91fd0849303a4eca033d660d0a7b6854.jpeg"},{"username":"homarr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16657003/medium/3afabfd3de949a54ff5d40ad04552aba.png"},{"username":"mwgg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16658379/medium/763dd09f5c238cc5324d4d5357985292.png"},{"username":"kiwinho","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16671855/medium/bfe3a2d497dc4748a04d02e4ae2139cb.jpeg"},{"username":"tjvg4m34r13","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16679135/medium/7a483b9b0abe0d925e54808e1cb38fa0.jpeg"},{"username":"Diegoem","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16705921/medium/29ce68ebc191fc3f65499511b12de98f_default.png"},{"username":"bouks69","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16746091/medium/b58b1fc08520de416198be9df5d093eb.jpeg"},{"username":"futhgar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16748067/medium/b8c526b097f9aa9d687250cac3df16dc.jpeg"},{"username":"GrimSQL","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16764343/medium/fff729a76d1f8fbcdaee9bb0c0f5f3fd.png"},{"username":"chnikel","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767047/medium/3dda2a37e03049dafefe6697bb00f75c.png"},{"username":"yuki19870616","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767951/medium/f59c848e38382cda6c8464b0a7b9e642_default.png"},{"username":"noamdal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16782245/medium/b4a72a61f9caf138f0322c0cb987e6d0.png"},{"username":"MalithRukshan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16809057/medium/084d6a5b35fbbeacc70e7021197d222f.png"},{"username":"minirope19","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16930929/medium/e8cbbc26747e31c5a8959215e1dd067b.jpeg"},{"username":"prubin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17503492/medium/96ac87644691e49c1f983f2f094e541c_default.png"},{"username":"sam-tam-sam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17578052/medium/1628dc2954ce3ae95e0caaa2bd60ab0c.png"},{"username":"toineenzo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12371852/medium/9f1b2bedb4794c59479cd289bdba9fab.png"},{"username":"ArcaneWater","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12421105/medium/1ac82517a6c658f6b62c48aebcb17e86_default.png"},{"username":"Ebedami","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12974801/medium/b596dea5c09454c4c828eac558389755.jpg"},{"username":"perrygamerptyt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13117177/medium/1406c949507ecd438480473c8a1f6124.jpg"},{"username":"SergiSvK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13320543/medium/3df3c79cc5f0c53716c559cd3fd2fc20.png"},{"username":"jeongeon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13362856/medium/eb572f72cde5e5526c517ca3a6489850_default.png"},{"username":"MrTranCFCVN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13439475/medium/a1789d69c85d90c667194b5d6a518c08_default.png"},{"username":"Tobost06","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13467449/medium/9227dc07f6366bc060d28304f5cb8ce7.jpeg"},{"username":"Kf637","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13530622/medium/118b00bb72d01d3229c97409637e25d1_default.png"},{"username":"Cruellest","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13610615/medium/2a74faa0947ee08d18f7946fb8602c1e.jpg"},{"username":"olavinto","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14424644/medium/37c01732bd2b7a272b421807a05ccfeb.png"},{"username":"Thario","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14491372/medium/dd5e142070802a672900121aa3f332a6_default.png"},{"username":"Wjouter","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14585620/medium/b91a51513332bdc0a0a9ecbed99ecbc3.png"},{"username":"albanobattistella","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14686194/medium/564afcfd76f5cd24751bd669cf4943aa.jpg"},{"username":"Kachelkaiser","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14763406/medium/203a781797da4a18fe0f4e7db8fd547c.png"},{"username":"regi4","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14842936/medium/f7e1d672f562a7db61ba6b4b8f4de41d.png"},{"username":"baton5129","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14891064/medium/8d438f557b82977dd02f0ead3187265f.PNG"},{"username":"meviper","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15958903/medium/209f521ce33a05831fa8d7d1b7babc20_default.png"},{"username":"GerOriki","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16268376/medium/da00e54b08cd40348231d92873a0cd0a_default.png"},{"username":"TheRedCyclops","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16486399/medium/7f39226180120d5a9efcb8e13d8aec8e_default.png"},{"username":"dymek37","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16659221/medium/d1dc6d11d7e7fc370efc5070e837ae03.png"},{"username":"B3CKDOOR","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16744975/medium/e6c7b2d45e76465d54e6efb67c83da7d.png"},{"username":"on9686","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16768173/medium/6282fed9aafe0262a173a5ec0887e5d9_default.png"},{"username":"Larsluph","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16779933/medium/ed7d36f8b44013bad3a16ac0491bd0f7.png"},{"username":"FOEDI","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16781001/medium/6b4552fb72e359aa016f7a054078fac8.png"},{"username":"xmarkurion","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16805443/medium/34a20428427de5aaef99c7d140646803.png"},{"username":"gregid","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16806705/medium/f3c8f4a20436e8538929130142bbc104.png"},{"username":"Flameberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16820453/medium/d47be866148474c9d05fec6fbe406d88.png"},{"username":"Playfust","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16872865/medium/5f4609cc711e5fb9fa8a0b178635769c.jpeg"},{"username":"Cotignac","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16879297/medium/81ff353edf030699a159bb79cda26e84.jpg"},{"username":"LeaHun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16916375/medium/618520f0543b1e212ebc83d66b683d4b_default.png"},{"username":"jackwellerreal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16919717/medium/37bbfdc03893f141133ccc619593266d.png"},{"username":"renan.costaalencar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16938427/medium/6d25b25320c5bde734118dec4af9cd5b.png"},{"username":"andrius.cim","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16967845/medium/46028fc1a0ddfaaeebcb37b39739625d_default.png"},{"username":"xjxexrxrxyx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17041412/medium/d34d664166db6fb25579bca9ff3b50b4.jpeg"},{"username":"bilhal.fellah","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17044572/medium/d1ec6f17e4aa013e9eededc83778d2c6.png"},{"username":"the_octo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17058060/medium/7423ab3a4cabb67f5decb2e2dfa2b675_default.png"},{"username":"BamesJond","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17075846/medium/128d7ffd40254c8e376f45678e2fc620_default.png"},{"username":"Kornikus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17134240/medium/d7a42b2c30db46ff152699ca01f9e11a_default.png"},{"username":"xoxyuxu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17176526/medium/108055aa24343043de852e412bec74be.png"},{"username":"cryptodntsleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17249408/medium/b9e15aa2b24a0dbc1e4f194aa8ed5109.png"},{"username":"yaniorg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17261842/medium/7dbfc77f21c826845961243c44540d26.jpg"},{"username":"Vidariondr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17262438/medium/45fbc71be02ef27296b6f423e97b6a03_default.png"},{"username":"Fastery","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17263066/medium/701b0edc59676174863ad651528bbb37.jpeg"},{"username":"stratself","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17290388/medium/57d9d8161b3fd0abf4dc5558b4a1fa05_default.png"},{"username":"wuzeqin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17292606/medium/b9e0308410b31337e2d7aa6ed346d718_default.png"},{"username":"ChristopherBull","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17304338/medium/21a175ce596bfae81430767467908b90.jpeg"},{"username":"darkbcnlord","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17311436/medium/b271bc0b419ec3a26ddb7b63ff8ffc4b.png"},{"username":"zhoran1997","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17344028/medium/c8f450b5a8f1e9494a45dc60af7ce63e.png"},{"username":"Pakura","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17396930/medium/18602738018348bf2ffa83a78bf165e2_default.png"},{"username":"gilalves1703","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17447768/medium/3f1de562a5c2391c88bbf8d5cf40a266.png"},{"username":"iServeCloud","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17470960/medium/11649b99d609438d66455a4d2fdc70f7.png"},{"username":"guibolzantvbox","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17474136/medium/59a576e6da538664ceb972253916fa02.jpeg"},{"username":"ivann136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17506062/medium/67d09ada36fac5f444a1f7517e3a97bd_default.png"},{"username":"Maheshivara","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17516082/medium/576e1e6581cf969615b265de6aeff8b7.jpeg"},{"username":"brunogui81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17517542/medium/7c0d174e810435af518fe8e0c05e151f.jpeg"},{"username":"michelwilhelm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17542190/medium/4c6b33fd8993ff565fa75add2ce8355e.jpeg"},{"username":"dias-gxstavo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17547376/medium/8c6b109aae8aeb651192346a39ae9e5b.jpeg"},{"username":"ToxykAuBleu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17614030/medium/8d21e0608560172b121bd46126d827c7.jpeg"},{"username":"e.erdemir","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17617994/medium/7259a29db9941c6171a8cbbd643b92bd.png"},{"username":"sjonkreutz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17618306/medium/7601c45d015189a863656e21348d223b.png"},{"username":"volovich0377","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17620388/medium/c929a8fbd24f96d17620fa497ade7309.png"},{"username":"Hamstio1","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17624898/medium/406e0bf40094c24a01c3064f8f5b2a82.png"},{"username":"i3laa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17627462/medium/613a9d283ed8b69819ee181903851660.jpeg"},{"username":"bastiengrignon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17629884/medium/ddfc3339285bd65195fcd834e512e9b7.jpeg"},{"username":"kauhee","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17644600/medium/def1b9066cf9275b4273a5a5dca7f325.png"},{"username":"hongminzheng","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17683860/medium/a764f4963912777d27a7cd98e136a2b2.png"},{"username":"d-lindahl","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17726729/medium/cbde348582fbabcfadd89a56cd5a0b40.png"},{"username":"Enoal-Fauchille-Bolle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17734649/medium/6e6fb29198782dc7856ea21811db669c.jpeg"},{"username":"manos-grigorakis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17737973/medium/b37f685587c920c81fdaf9a357962434.jpeg"},{"username":"SertraFurr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17738703/medium/5f1e9f270e315ee3185cf2ccb3f5a833.png"},{"username":"Kle.Ma","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17739207/medium/b767d6093e6608f251ca152f53d359b8_default.png"},{"username":"WalkerLukas","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17744485/medium/87508ce83a9b6e5391f55883a66a054b.png"},{"username":"mtya","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17748447/medium/f574d5a770d74814f8c49ee68e00f5b7.jpeg"},{"username":"Elaktrato","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17750977/medium/f4109d379f29dc8ea2e7799ac9e208c8.png"},{"username":"marcelmeis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17753627/medium/4ba32116c27e427d3073e45713f6564e.png"}] \ No newline at end of file +[{"username":"carlchina","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png"},{"username":"zielmann","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png"},{"username":"Thalyn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png"},{"username":"magnushj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png"},{"username":"almontegil","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png"},{"username":"andibing","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg"},{"username":"gronare","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png"},{"username":"SmartPhoneLover","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg"},{"username":"marcelotk_15","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png"},{"username":"S3OD177","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png"},{"username":"marcg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png"},{"username":"BeersTeddy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png"},{"username":"jamesmcmahon0","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg"},{"username":"b1nar10","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/aaa1f083e04c572f953fde4563171e4a.jpeg"},{"username":"vannCN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg"},{"username":"binswm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png"},{"username":"SkewRam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg"},{"username":"raphcatarino","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg"},{"username":"shillos5","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg"},{"username":"wolong98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg"},{"username":"spair0039","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png"},{"username":"MajorMarcin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg"},{"username":"KosmoMoustache","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png"},{"username":"Soochaehwa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png"},{"username":"garryfield","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg"},{"username":"droidenko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg"},{"username":"maathis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg"},{"username":"bukvam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg"},{"username":"gm.cinalli","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg"},{"username":"antoine2tt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png"},{"username":"cretzen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg"},{"username":"ktKongTong","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg"},{"username":"marinkaberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14861042/medium/2d5c4e62613f03082f3e645fa92efd59.jpeg"},{"username":"djismgaming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14934947/medium/f5a8570713c34ab0f7d5405d105e2a9a.jpeg"},{"username":"f1refa11","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14949159/medium/fd2ae63b8eb4462200ba96abf943c1b9.png"},{"username":"jeffersonraimon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057621/medium/6dff469563860e2618bc9d45646d0ab4.png"},{"username":"giop98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057987/medium/b8a4825d3fc39fc662f35ee258db4b2d.jpeg"},{"username":"tomislav.kraljevic","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15118857/medium/e133f1061cc92850b854d05d8faaeafd.png"},{"username":"Walkx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15202182/medium/5c37361ae45aeed487b34582c1f7ca37.png"},{"username":"andrea.rosso","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15246318/medium/11f3f5ef44ec7f55b6f143090e208704_default.png"},{"username":"ajnart","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15270132/medium/a0f107a463c8910ee96bc2fa843a17e3.jpeg"},{"username":"Witchling","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15282238/medium/9e196b6783415b10ca571b7673c2ef33.jpg"},{"username":"guineuu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15292058/medium/22fbb758bda3b7805d50bf21d38f2c20.jpeg"},{"username":"Bulgus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15304568/medium/0e8787e5ceb02ed5c96a514d0068ae87.jpg"},{"username":"Narno","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15314996/medium/a6ba093f24884250a1bf6c6f2ca50f1b_default.png"},{"username":"BySempron","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15315986/medium/e3d22d7b1423c6823a9f36d595ed4bdb.png"},{"username":"jonathan.berglin.work","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15359236/medium/95930b2093db13b76179782f7322c5d5.png"},{"username":"icdmkg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405504/medium/f334d16cde1ac4ffb935b440d03465af.gif"},{"username":"irithys","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405614/medium/3086461c47cce0a0c031925e5f943412.png"},{"username":"JannesV","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419912/medium/a7809eb4b817d7c49b62cf10ae86b950.png"},{"username":"benniblot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419914/medium/8086b1573d31f152ba41949b3a172445.jpeg"},{"username":"pacjo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419916/medium/3cbeddbd7bc01faafb5a3bf47bba915b_default.png"},{"username":"Payou6994","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419934/medium/37c9b9b17dfb578404c1c1ddb73ba7a8.png"},{"username":"fzibi21","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419976/medium/0da688450358e0290a7b7359cc1f7328.png"},{"username":"WowMurdock","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420118/medium/de19576fccb495b6dfe4c4c04a56b834.png"},{"username":"hbooo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420120/medium/6c7c7f8db785061356ebb03d044d3329.jpeg"},{"username":"Manicraft1001","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420178/medium/50ec94563a06a9f74f33bd09f01eed4d.jpg"},{"username":"Void123","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420354/medium/86929d44df92a00f9fe900a985c196df_default.png"},{"username":"R4cc","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15422606/medium/a390979662b84694f59de30bdb732141.jpeg"},{"username":"fabricionaweb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15425808/medium/a9354142e7ae5152c144409d55fda551_default.png"},{"username":"JokeOfDead","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15426890/medium/a383eac9365e9de64fd4ab1d6fd0cb95.jpeg"},{"username":"hkz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15427174/medium/c88acefb0d7306e1f7470e872029fb39_default.png"},{"username":"Steken","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428516/medium/d5aea5653c769c3a523182bdb60d1664.png"},{"username":"flar.anton","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428592/medium/b01fdb365d892e9f811f77fcb50a80a2.jpeg"},{"username":"Bon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15433542/medium/5397da4dfc821f20b6ac14fe0c514e9a.jpeg"},{"username":"bfkadan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434162/medium/4f9a0b43cfe3acaea60124c14ba7f44a.png"},{"username":"BunnySweety","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434662/medium/f0ef200a6a0dcf0e1d0e9ecd4148f560_default.png"},{"username":"HRKings","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15436168/medium/69a31e461d38549f01864e7ef10d642e.png"},{"username":"wiston81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15439078/medium/10f292c8d12a7c21a44b54495fa4a3d8.jpeg"},{"username":"qaz0911","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15440860/medium/3d3e50ee388c72dc4bf7a771761f2d89_default.png"},{"username":"qqyule","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15441462/medium/7a3cdf82710ffb5d8f388bc0bd010665.png"},{"username":"Bims0n","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15445560/medium/603220b603eeb3367e0f0d3fa675247c.jpg"},{"username":"TariqDaCoder","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15446228/medium/50b0f4040112bbd67690b769477398e5_default.png"},{"username":"Anarchon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15449644/medium/e925e1f3e3ffbf0f982391ce263a1a28.jpeg"},{"username":"Ashun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15453020/medium/ccdcf51c73d6aae40751bb30beee1915_default.png"},{"username":"sebekmartin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15454038/medium/bcfb44598cdfd1d7cd4eb35812538962.jpeg"},{"username":"RagnarGraves","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15459882/medium/143d5af850c1154070a218bea124e9cb_default.png"},{"username":"PrtmPhlp","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15462414/medium/b80db55e9de301432dcd1f8c8b24fd49_default.png"},{"username":"DooYoo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15470768/medium/2a18cf4be67094724b508c9e1e698a21_default.png"},{"username":"espentruls","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486092/medium/8e38afc3a4ff669226a0cfd3e420ff3a.jpeg"},{"username":"frisco82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486922/medium/4e1c5d4189b42508e660daa3c1c25b2a.jpeg"},{"username":"lupineDK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15491798/medium/461bd501e8371c062bf29ea171aedd36_default.png"},{"username":"hillaliy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15492732/medium/0bae17b421604892d888e3fc70cf0587.jpeg"},{"username":"MarcOrfilaCarreras","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15501072/medium/ea52b26c3c6f21e4931e38e3ce3f3d6e.png"},{"username":"robertbridda","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15507822/medium/a368c2e30411bb2da9b49290084191f3.png"},{"username":"MKoniuszko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518090/medium/87605434fcc839f6763ab07c50f6d232.jpeg"},{"username":"HeroSizy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518710/medium/4e79c0e98cbeb536dd961e656331b509.png"},{"username":"dwt136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15520022/medium/554422503f2baea43ace85facb4546fb_default.png"},{"username":"asifthewebguy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15526719/medium/b18931dd0c800d725048bd440646198b_default.png"},{"username":"eiloogs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15545537/medium/f290a2f1190983530a9b76b2e858a609.gif"},{"username":"_vytdv","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15547289/medium/60d8644cc8ad6f11a92ccea4a14cd098_default.png"},{"username":"crendasien","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15554645/medium/598ab1d4aaf6b8dccd5ba16be92da7b9.jpeg"},{"username":"edxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15573823/medium/8a565b732a75a77f840dd123cdb30bf4.png"},{"username":"somerlev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15617065/medium/f4b13513e311ec902d90b2f718412c55.jpg"},{"username":"kid1412621","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15643771/medium/dd455e32de652fa88e6fd97598bdffa7.png"},{"username":"suming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15644717/medium/244159dfe10fa03436205506f80c9e25.png"},{"username":"nick.gher","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15647517/medium/5374a2c6fef60a3fbf0edf86b997c351_default.png"},{"username":"DataCat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15650315/medium/ce7c1365adf35c5d490d77500a4607fb_default.png"},{"username":"dizo89","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15658375/medium/0ca745e5017d491fe1b22b0239904de8.jpeg"},{"username":"tee_noodle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674577/medium/804d9cf06f5196026acb6436b809d0da_default.png"},{"username":"Marty88","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674593/medium/492b1509d52bd2809dea768121217125.jpeg"},{"username":"Spillebulle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15677023/medium/20b98bb85062e07afe0e63618f8a5feb.PNG"},{"username":"petitmewen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15685239/medium/15de9b62d2e0bc25013435f1784bbcc1.jpeg"},{"username":"NoProsNoNoobs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15687709/medium/ae8f65fafeb8bcf74dcb8871bbe46461.png"},{"username":"y.gybson","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15690777/medium/b5cb5d2d5768904ff6586c727e3a6c77.jpeg"},{"username":"inside90","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15704947/medium/c1355fcb30dd76f8e39d98d1d49f1c52.png"},{"username":"RJSkudra","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15709853/medium/c3abf2774913dc4e81fb261d36d7668c.png"},{"username":"binge203","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15713937/medium/77c1cfa4314673db80e6881fd9f64668.gif"},{"username":"Mailootje","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15714337/medium/743c3bc4ab1989966a375eeeec83d8b8.jpeg"},{"username":"tim-wiegers","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15719805/medium/08a96f064813350661cd6b20bf3d7d99.png"},{"username":"GkhnG","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15722911/medium/71a027caec489ef6ce82bcf1888329d0_default.png"},{"username":"Zoen-Millo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15760967/medium/9e956f11adc5b34f5636268b5c485dbf.jpg"},{"username":"HooinKyoma","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15792897/medium/9489f0a9b368e0e827ae758b740a2eed.jpeg"},{"username":"wathergeen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15794495/medium/a83b7fc80d180669ebfd6deb3544cfd0.png"},{"username":"MoeToo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15818233/medium/d35cd6953717706eaf20f6c143c62947.png"},{"username":"itodouble","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15836233/medium/e984caea18fb0673bf319fcf28cef649.png"},{"username":"loslocitos","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15847901/medium/fe30d12fd2cf38212f929e13b169f9ec.jpeg"},{"username":"Oversleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15849065/medium/06141f13a6d541d753f3c2f2947b8068_default.png"},{"username":"Beardy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15865139/medium/fca6b9d2b3f52e286d1568f52b83b6a0_default.png"},{"username":"raelyan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15875457/medium/2f4fda1d1aaa5dcc79b328baf3f03151.jpeg"},{"username":"dolphin738","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15913763/medium/ee6fede7b8528ca642329ada80d1cc18.png"},{"username":"brunotco","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15916719/medium/09db45880fc05abc18adb8d932a5ecf9_default.png"},{"username":"LukeIsHereToDevelop","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15924739/medium/3e6cd3940297bb4ba7bb039c93e6f918.png"},{"username":"kennit","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15925879/medium/6b0733ad3c5949b91c55e4d8b03db8a5_default.png"},{"username":"kuunpire","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15950309/medium/8192a4f08f07086828ac9f74ed29a169.jpeg"},{"username":"Sandor-dev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15951759/medium/0216c2da4eb028164ebbecf1c72f6271_default.png"},{"username":"Meierschlumpf","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15953187/medium/23c744faef1ab84fbdc9351a7850aab6.jpeg"},{"username":"harmlesscat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15970733/medium/dd8d0214a0250c932bb518b1b55e45a2_default.png"},{"username":"OrzWTF","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15976121/medium/4c4557cbff7ff7b0503455bc59c020e0.jpeg"},{"username":"tagaishi","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15977271/medium/eade504c83a5a1ff831c80a538fbdb44_default.png"},{"username":"azurite928","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15981895/medium/547ccc459ee123e78b5401c499f1022d.png"},{"username":"Ronner231","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16021342/medium/7734d550df2de5a2fec2ffff33e7024c.jpeg"},{"username":"ugyes","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16034148/medium/ed001e3f470a2dea9a8ce955b18e7bd5.png"},{"username":"rpieja","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16045554/medium/bd55baca2ef8b92502a760cc9ee7c505_default.png"},{"username":"flambyisyou","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16051620/medium/3a3bc0c90f6b95ab4ef74396a0a17beb.png"},{"username":"Topbcy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16077170/medium/d3aed33ea56330338756cfcd89477cfe.jpeg"},{"username":"ai5d02sb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16084674/medium/7c8119fe2a5ca71bb15f636916a42b95_default.png"},{"username":"explosiveparrot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16097722/medium/7762f80fc1da63f5b2eb87de9d640324_default.png"},{"username":"DestroyCom","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16111544/medium/83e3d3ac5c8bfed634cd1a074854db67.png"},{"username":"neotraxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16116966/medium/b30df957873329019a8a90a69f6efe3a.png"},{"username":"gzxpa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16123314/medium/487b05577310a946b0b98bc72c11213b_default.png"},{"username":"TORIK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16124732/medium/de770890e6411860ac06e8cc2dc0abd0_default.png"},{"username":"sergio.pibot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16138114/medium/80db802b2fcd6bbf19ea4c7413367dca.jpeg"},{"username":"karam-ajaj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16139838/medium/7539ab958d3c85d5f67e7849483ea8f7.jpeg"},{"username":"SimonHenz97","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16151520/medium/9b94a85b536688e2d94538c384fd0a76.png"},{"username":"olsson82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16198988/medium/eeaab4cba210c537424d4204754b604e.png"},{"username":"bo3bdo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16222806/medium/8652f3beacb6098dde5a4cd0a29fe80d.jpeg"},{"username":"AngryPlayer04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245192/medium/342715274f4dc31fd4132cdae9126188.jpeg"},{"username":"ehatamm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245884/medium/979d5e5526fe545be9bf46db481f7182.jpeg"},{"username":"Balionelis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16246058/medium/986d62ba363594c517d966fe9178dcbb.png"},{"username":"kwargs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16248816/medium/19ce11f04bf1ae2637e0483399c675f9_default.png"},{"username":"lucicu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16273892/medium/3b09e8f3bead221ef98d6a45a16851dc_default.png"},{"username":"Michael5564445","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16357688/medium/9d9026a8bf3eaccb0417da240932ebf7.png"},{"username":"Netscream","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16359198/medium/694e0c8572dc8a47e6d63da31ec5b992.png"},{"username":"belicstefan04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16368142/medium/4742dcfd7bf7ad7e33e37ac44fba7e0f.png"},{"username":"Hamad2066","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16371478/medium/f37bbc7685b6757defdbd1494236af61.jpeg"},{"username":"3ct0pl4sm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16399616/medium/ce796d1c40163975624c0a483e56374f.png"},{"username":"sanchez.marcell626","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16433865/medium/3ddde1314764cc2205ffdcd1ae719a91.png"},{"username":"Minoctis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16490079/medium/91fd0849303a4eca033d660d0a7b6854.jpeg"},{"username":"homarr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16657003/medium/3afabfd3de949a54ff5d40ad04552aba.png"},{"username":"mwgg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16658379/medium/763dd09f5c238cc5324d4d5357985292.png"},{"username":"kiwinho","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16671855/medium/bfe3a2d497dc4748a04d02e4ae2139cb.jpeg"},{"username":"tjvg4m34r13","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16679135/medium/7a483b9b0abe0d925e54808e1cb38fa0.jpeg"},{"username":"Diegoem","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16705921/medium/29ce68ebc191fc3f65499511b12de98f_default.png"},{"username":"bouks69","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16746091/medium/b58b1fc08520de416198be9df5d093eb.jpeg"},{"username":"futhgar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16748067/medium/b8c526b097f9aa9d687250cac3df16dc.jpeg"},{"username":"GrimSQL","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16764343/medium/fff729a76d1f8fbcdaee9bb0c0f5f3fd.png"},{"username":"chnikel","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767047/medium/3dda2a37e03049dafefe6697bb00f75c.png"},{"username":"yuki19870616","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767951/medium/f59c848e38382cda6c8464b0a7b9e642_default.png"},{"username":"noamdal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16782245/medium/b4a72a61f9caf138f0322c0cb987e6d0.png"},{"username":"MalithRukshan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16809057/medium/084d6a5b35fbbeacc70e7021197d222f.png"},{"username":"minirope19","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16930929/medium/e8cbbc26747e31c5a8959215e1dd067b.jpeg"},{"username":"prubin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17503492/medium/96ac87644691e49c1f983f2f094e541c_default.png"},{"username":"sam-tam-sam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17578052/medium/1628dc2954ce3ae95e0caaa2bd60ab0c.png"},{"username":"KydoxOwn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17764383/medium/0bc150a09d77f5fda43988e6342777dc.png"},{"username":"toineenzo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12371852/medium/9f1b2bedb4794c59479cd289bdba9fab.png"},{"username":"ArcaneWater","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12421105/medium/1ac82517a6c658f6b62c48aebcb17e86_default.png"},{"username":"Ebedami","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12974801/medium/b596dea5c09454c4c828eac558389755.jpg"},{"username":"perrygamerptyt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13117177/medium/1406c949507ecd438480473c8a1f6124.jpg"},{"username":"SergiSvK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13320543/medium/3df3c79cc5f0c53716c559cd3fd2fc20.png"},{"username":"jeongeon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13362856/medium/eb572f72cde5e5526c517ca3a6489850_default.png"},{"username":"MrTranCFCVN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13439475/medium/a1789d69c85d90c667194b5d6a518c08_default.png"},{"username":"Tobost06","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13467449/medium/9227dc07f6366bc060d28304f5cb8ce7.jpeg"},{"username":"Kf637","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13530622/medium/118b00bb72d01d3229c97409637e25d1_default.png"},{"username":"Cruellest","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13610615/medium/2a74faa0947ee08d18f7946fb8602c1e.jpg"},{"username":"olavinto","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14424644/medium/37c01732bd2b7a272b421807a05ccfeb.png"},{"username":"Thario","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14491372/medium/dd5e142070802a672900121aa3f332a6_default.png"},{"username":"Wjouter","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14585620/medium/b91a51513332bdc0a0a9ecbed99ecbc3.png"},{"username":"albanobattistella","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14686194/medium/564afcfd76f5cd24751bd669cf4943aa.jpg"},{"username":"Kachelkaiser","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14763406/medium/203a781797da4a18fe0f4e7db8fd547c.png"},{"username":"regi4","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14842936/medium/f7e1d672f562a7db61ba6b4b8f4de41d.png"},{"username":"baton5129","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14891064/medium/8d438f557b82977dd02f0ead3187265f.PNG"},{"username":"meviper","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15958903/medium/209f521ce33a05831fa8d7d1b7babc20_default.png"},{"username":"GerOriki","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16268376/medium/da00e54b08cd40348231d92873a0cd0a_default.png"},{"username":"TheRedCyclops","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16486399/medium/7f39226180120d5a9efcb8e13d8aec8e_default.png"},{"username":"dymek37","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16659221/medium/d1dc6d11d7e7fc370efc5070e837ae03.png"},{"username":"B3CKDOOR","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16744975/medium/e6c7b2d45e76465d54e6efb67c83da7d.png"},{"username":"on9686","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16768173/medium/6282fed9aafe0262a173a5ec0887e5d9_default.png"},{"username":"Larsluph","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16779933/medium/ed7d36f8b44013bad3a16ac0491bd0f7.png"},{"username":"FOEDI","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16781001/medium/6b4552fb72e359aa016f7a054078fac8.png"},{"username":"xmarkurion","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16805443/medium/34a20428427de5aaef99c7d140646803.png"},{"username":"gregid","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16806705/medium/f3c8f4a20436e8538929130142bbc104.png"},{"username":"Flameberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16820453/medium/d47be866148474c9d05fec6fbe406d88.png"},{"username":"Playfust","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16872865/medium/5f4609cc711e5fb9fa8a0b178635769c.jpeg"},{"username":"Cotignac","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16879297/medium/81ff353edf030699a159bb79cda26e84.jpg"},{"username":"LeaHun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16916375/medium/618520f0543b1e212ebc83d66b683d4b_default.png"},{"username":"jackwellerreal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16919717/medium/37bbfdc03893f141133ccc619593266d.png"},{"username":"renan.costaalencar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16938427/medium/6d25b25320c5bde734118dec4af9cd5b.png"},{"username":"andrius.cim","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16967845/medium/46028fc1a0ddfaaeebcb37b39739625d_default.png"},{"username":"xjxexrxrxyx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17041412/medium/d34d664166db6fb25579bca9ff3b50b4.jpeg"},{"username":"bilhal.fellah","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17044572/medium/d1ec6f17e4aa013e9eededc83778d2c6.png"},{"username":"the_octo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17058060/medium/7423ab3a4cabb67f5decb2e2dfa2b675_default.png"},{"username":"BamesJond","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17075846/medium/128d7ffd40254c8e376f45678e2fc620_default.png"},{"username":"Kornikus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17134240/medium/d7a42b2c30db46ff152699ca01f9e11a_default.png"},{"username":"Master3307","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17161852/medium/94ec577dd53e16b434f2aac9c34f64c6.png"},{"username":"xoxyuxu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17176526/medium/108055aa24343043de852e412bec74be.png"},{"username":"cryptodntsleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17249408/medium/b9e15aa2b24a0dbc1e4f194aa8ed5109.png"},{"username":"yaniorg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17261842/medium/7dbfc77f21c826845961243c44540d26.jpg"},{"username":"Vidariondr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17262438/medium/45fbc71be02ef27296b6f423e97b6a03_default.png"},{"username":"Fastery","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17263066/medium/701b0edc59676174863ad651528bbb37.jpeg"},{"username":"stratself","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17290388/medium/57d9d8161b3fd0abf4dc5558b4a1fa05_default.png"},{"username":"wuzeqin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17292606/medium/b9e0308410b31337e2d7aa6ed346d718_default.png"},{"username":"ChristopherBull","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17304338/medium/21a175ce596bfae81430767467908b90.jpeg"},{"username":"darkbcnlord","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17311436/medium/b271bc0b419ec3a26ddb7b63ff8ffc4b.png"},{"username":"zhoran1997","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17344028/medium/c8f450b5a8f1e9494a45dc60af7ce63e.png"},{"username":"Pakura","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17396930/medium/18602738018348bf2ffa83a78bf165e2_default.png"},{"username":"gilalves1703","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17447768/medium/3f1de562a5c2391c88bbf8d5cf40a266.png"},{"username":"iServeCloud","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17470960/medium/11649b99d609438d66455a4d2fdc70f7.png"},{"username":"guibolzantvbox","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17474136/medium/59a576e6da538664ceb972253916fa02.jpeg"},{"username":"ivann136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17506062/medium/67d09ada36fac5f444a1f7517e3a97bd_default.png"},{"username":"Maheshivara","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17516082/medium/576e1e6581cf969615b265de6aeff8b7.jpeg"},{"username":"brunogui81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17517542/medium/7c0d174e810435af518fe8e0c05e151f.jpeg"},{"username":"michelwilhelm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17542190/medium/4c6b33fd8993ff565fa75add2ce8355e.jpeg"},{"username":"dias-gxstavo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17547376/medium/8c6b109aae8aeb651192346a39ae9e5b.jpeg"},{"username":"ToxykAuBleu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17614030/medium/8d21e0608560172b121bd46126d827c7.jpeg"},{"username":"e.erdemir","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17617994/medium/7259a29db9941c6171a8cbbd643b92bd.png"},{"username":"sjonkreutz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17618306/medium/7601c45d015189a863656e21348d223b.png"},{"username":"volovich0377","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17620388/medium/c929a8fbd24f96d17620fa497ade7309.png"},{"username":"Hamstio1","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17624898/medium/406e0bf40094c24a01c3064f8f5b2a82.png"},{"username":"i3laa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17627462/medium/613a9d283ed8b69819ee181903851660.jpeg"},{"username":"bastiengrignon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17629884/medium/ddfc3339285bd65195fcd834e512e9b7.jpeg"},{"username":"kauhee","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17644600/medium/def1b9066cf9275b4273a5a5dca7f325.png"},{"username":"hongminzheng","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17683860/medium/a764f4963912777d27a7cd98e136a2b2.png"},{"username":"d-lindahl","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17726729/medium/cbde348582fbabcfadd89a56cd5a0b40.png"},{"username":"Enoal-Fauchille-Bolle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17734649/medium/6e6fb29198782dc7856ea21811db669c.jpeg"},{"username":"manos-grigorakis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17737973/medium/b37f685587c920c81fdaf9a357962434.jpeg"},{"username":"SertraFurr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17738703/medium/5f1e9f270e315ee3185cf2ccb3f5a833.png"},{"username":"Kle.Ma","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17739207/medium/b767d6093e6608f251ca152f53d359b8_default.png"},{"username":"WalkerLukas","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17744485/medium/87508ce83a9b6e5391f55883a66a054b.png"},{"username":"mtya","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17748447/medium/f574d5a770d74814f8c49ee68e00f5b7.jpeg"},{"username":"Elaktrato","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17750977/medium/f4109d379f29dc8ea2e7799ac9e208c8.png"},{"username":"marcelmeis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17753627/medium/4ba32116c27e427d3073e45713f6564e.png"},{"username":"ProKafelek12e","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17760377/medium/5199af152f1ea42cee718e7729bd41ff.png"},{"username":"zalaghi","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17763367/medium/a06f7b15222663517b58b8dc8902f8a1.png"}] \ No newline at end of file diff --git a/tooling/github/setup/action.yml b/tooling/github/setup/action.yml index b426ed746..77ff8d742 100644 --- a/tooling/github/setup/action.yml +++ b/tooling/github/setup/action.yml @@ -7,7 +7,7 @@ runs: - uses: pnpm/action-setup@v6 - uses: actions/setup-node@v6 with: - node-version: 24.16.0 + node-version: 24.17.0 cache: "pnpm" - shell: bash