diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0653e1f75..f0cdbe63c 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,7 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "yoavbls.pretty-ts-errors", - "million.million-lint" + "million.million-lint", + "lokalise.i18n-ally" ] } diff --git a/.vscode/i18n-ally-custom-framework.yml b/.vscode/i18n-ally-custom-framework.yml new file mode 100644 index 000000000..6cb944e00 --- /dev/null +++ b/.vscode/i18n-ally-custom-framework.yml @@ -0,0 +1,36 @@ +# .vscode/i18n-ally-custom-framework.yml + +# An array of strings which contain Language Ids defined by VS Code +# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers +languageIds: + - javascript + - typescript + - javascriptreact + - typescriptreact + +# An array of RegExes to find the key usage. **The key should be captured in the first match group**. +# You should unescape RegEx strings in order to fit in the YAML file +# To help with this, you can use https://www.freeformatter.com/json-escape.html +usageMatchRegex: + # The following example shows how to detect `t("your.i18n.keys")` + # the `{key}` will be placed by a proper keypath matching regex, + # you can ignore it and use your own matching rules as well + - "[^\\w\\d]t\\(['\"`]({key})['\"`]" + +# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys +# and works like how the i18next framework identifies the namespace scope from the +# useTranslation() hook. +# You should unescape RegEx strings in order to fit in the YAML file +# To help with this, you can use https://www.freeformatter.com/json-escape.html +scopeRangeRegex: "(getScopedI18n|useScopedI18n)\\(\\s*['\"](.*?)['\"]\\)" + +# An array of strings containing refactor templates. +# The "$1" will be replaced by the keypath specified. +# Optional: uncomment the following two lines to use + +# refactorTemplates: +# - i18n.get("$1") + + +# If set to true, only enables this custom framework (will disable all built-in frameworks) +monopoly: true \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 28d5f189e..0cf8dc65f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,9 +27,12 @@ "Umami" ], "i18n-ally.dirStructure": "auto", - "i18n-ally.enabledFrameworks": ["next-intl"], - "i18n-ally.localesPaths": ["./packages/translation/src/lang/"], - "i18n-ally.enabledParsers": ["ts"], - "i18n-ally.extract.keyMaxLength": 0, - "i18n-ally.keystyle": "flat" + "i18n-ally.displayLanguage": "en", + "i18n-ally.enabledFrameworks": [ + "custom" + ], + "i18n-ally.localesPaths": [ + "packages/translation/src/lang", + ], + "i18n-ally.keystyle": "auto", } diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 291929ac2..abf9adb01 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -37,17 +37,17 @@ "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0", - "@mantine/colors-generator": "^7.14.0", - "@mantine/core": "^7.14.0", - "@mantine/hooks": "^7.14.0", - "@mantine/modals": "^7.14.0", - "@mantine/tiptap": "^7.14.0", + "@mantine/colors-generator": "^7.14.1", + "@mantine/core": "^7.14.1", + "@mantine/hooks": "^7.14.1", + "@mantine/modals": "^7.14.1", + "@mantine/tiptap": "^7.14.1", "@million/lint": "1.0.12", "@t3-oss/env-nextjs": "^0.11.1", "@tabler/icons-react": "^3.22.0", - "@tanstack/react-query": "^5.60.5", - "@tanstack/react-query-devtools": "^5.60.5", - "@tanstack/react-query-next-experimental": "5.60.5", + "@tanstack/react-query": "^5.61.0", + "@tanstack/react-query-devtools": "^5.61.0", + "@tanstack/react-query-next-experimental": "5.61.0", "@trpc/client": "next", "@trpc/next": "next", "@trpc/react-query": "next", @@ -61,7 +61,7 @@ "dotenv": "^16.4.5", "flag-icons": "^7.2.3", "glob": "^11.0.0", - "jotai": "^2.10.2", + "jotai": "^2.10.3", "mantine-react-table": "2.0.0-beta.7", "next": "^14.2.18", "postcss-preset-mantine": "^1.17.0", @@ -80,13 +80,13 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/chroma-js": "2.4.4", - "@types/node": "^22.9.0", + "@types/node": "^22.9.1", "@types/prismjs": "^1.26.5", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/swagger-ui-react": "^4.18.3", "concurrently": "^9.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "node-loader": "^2.1.0", "prettier": "^3.3.3", "typescript": "^5.6.3" diff --git a/apps/nextjs/public/images/apps/imdb.png b/apps/nextjs/public/images/apps/imdb.png deleted file mode 100644 index 9565159a4..000000000 Binary files a/apps/nextjs/public/images/apps/imdb.png and /dev/null differ diff --git a/apps/nextjs/public/images/apps/imdb.svg b/apps/nextjs/public/images/apps/imdb.svg new file mode 100644 index 000000000..b2a908bcb --- /dev/null +++ b/apps/nextjs/public/images/apps/imdb.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/nextjs/public/images/apps/lastfm.svg b/apps/nextjs/public/images/apps/lastfm.svg new file mode 100644 index 000000000..e38bfb7d3 --- /dev/null +++ b/apps/nextjs/public/images/apps/lastfm.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/apps/nextjs/public/images/apps/tmdb.png b/apps/nextjs/public/images/apps/tmdb.png deleted file mode 100644 index 9f983b883..000000000 Binary files a/apps/nextjs/public/images/apps/tmdb.png and /dev/null differ diff --git a/apps/nextjs/public/images/apps/tmdb.svg b/apps/nextjs/public/images/apps/tmdb.svg new file mode 100644 index 000000000..42f31f154 --- /dev/null +++ b/apps/nextjs/public/images/apps/tmdb.svg @@ -0,0 +1 @@ +Asset 2 \ No newline at end of file diff --git a/apps/nextjs/public/images/apps/vgmdb.svg b/apps/nextjs/public/images/apps/vgmdb.svg new file mode 100644 index 000000000..8439f025e --- /dev/null +++ b/apps/nextjs/public/images/apps/vgmdb.svg @@ -0,0 +1,47 @@ + + + + + + + + + + diff --git a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx index 6ddcd97e4..8a2e6c581 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx @@ -17,7 +17,7 @@ import { import superjson from "superjson"; import type { AppRouter } from "@homarr/api"; -import { clientApi } from "@homarr/api/client"; +import { clientApi, createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/client"; import { env } from "~/env.mjs"; @@ -86,16 +86,13 @@ export function TRPCReactProvider(props: PropsWithChildren) { return data; }, }, - url: `${getBaseUrl()}/api/trpc`, + url: getTrpcUrl(), + headers: createHeadersCallbackForSource("nextjs-react (form-data)"), }), false: unstable_httpBatchStreamLink({ transformer: superjson, - url: `${getBaseUrl()}/api/trpc`, - headers() { - const headers = new Headers(); - headers.set("x-trpc-source", "nextjs-react"); - return headers; - }, + url: getTrpcUrl(), + headers: createHeadersCallbackForSource("nextjs-react (json)"), }), }), }), @@ -112,9 +109,3 @@ export function TRPCReactProvider(props: PropsWithChildren) { ); } - -function getBaseUrl() { - if (typeof window !== "undefined") return window.location.origin; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; - return `http://localhost:${process.env.PORT ?? 3000}`; -} diff --git a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx index 9b3551e43..f5fbc5d6f 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx @@ -1,6 +1,8 @@ +import { notFound } from "next/navigation"; import { Container, Stack, Title } from "@mantine/core"; import { api } from "@homarr/api/server"; +import { auth } from "@homarr/auth/next"; import { getI18n } from "@homarr/translation/server"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; @@ -11,6 +13,11 @@ interface AppEditPageProps { } export default async function AppEditPage({ params }: AppEditPageProps) { + const session = await auth(); + + if (!session?.user.permissions.includes("app-modify-all")) { + notFound(); + } const app = await api.app.byId({ id: params.id }); const t = await getI18n(); diff --git a/apps/nextjs/src/app/[locale]/manage/apps/new/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/new/page.tsx index 9fe1a2de6..6b0cd029d 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/new/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/new/page.tsx @@ -1,11 +1,19 @@ +import { notFound } from "next/navigation"; import { Container, Stack, Title } from "@mantine/core"; +import { auth } from "@homarr/auth/next"; import { getI18n } from "@homarr/translation/server"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { AppNewForm } from "./_app-new-form"; export default async function AppNewPage() { + const session = await auth(); + + if (!session?.user.permissions.includes("app-create")) { + notFound(); + } + const t = await getI18n(); return ( diff --git a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx index 11aa2e8eb..2029fbafa 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx @@ -1,9 +1,11 @@ import Link from "next/link"; +import { redirect } from "next/navigation"; import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text, Title } from "@mantine/core"; import { IconApps, IconPencil } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; +import { auth } from "@homarr/auth/next"; import { parseAppHrefWithVariablesServer } from "@homarr/common/server"; import { getI18n, getScopedI18n } from "@homarr/translation/server"; @@ -13,6 +15,12 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { AppDeleteButton } from "./_app-delete-button"; export default async function AppsPage() { + const session = await auth(); + + if (!session) { + redirect("/auth/login"); + } + const apps = await api.app.all(); const t = await getScopedI18n("app"); @@ -22,9 +30,11 @@ export default async function AppsPage() { {t("page.list.title")} - - {t("page.create.title")} - + {session.user.permissions.includes("app-create") && ( + + {t("page.create.title")} + + )} {apps.length === 0 && } {apps.length > 0 && ( @@ -45,6 +55,7 @@ interface AppCardProps { const AppCard = async ({ app }: AppCardProps) => { const t = await getScopedI18n("app"); + const session = await auth(); return ( @@ -78,16 +89,18 @@ const AppCard = async ({ app }: AppCardProps) => { - - - - + {session?.user.permissions.includes("app-modify-all") && ( + + + + )} + {session?.user.permissions.includes("app-full-all") && } @@ -97,6 +110,7 @@ const AppCard = async ({ app }: AppCardProps) => { const AppNoResults = async () => { const t = await getI18n(); + const session = await auth(); return ( @@ -105,7 +119,9 @@ const AppNoResults = async () => { {t("app.page.list.noResults.title")} - {t("app.page.list.noResults.action")} + {session?.user.permissions.includes("app-create") && ( + {t("app.page.list.noResults.action")} + )} ); diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx index 4783014e2..ede3d7a71 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx @@ -6,7 +6,7 @@ import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { IntegrationAvatar } from "@homarr/ui"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; -import { catchTrpcNotFound } from "~/errors/trpc-not-found"; +import { catchTrpcNotFound } from "~/errors/trpc-catch-error"; import { IntegrationAccessSettings } from "../../_components/integration-access-settings"; import { EditIntegrationForm } from "./_integration-edit-form"; diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx index fafc49fc8..a600effed 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx @@ -1,6 +1,7 @@ import { Fragment } from "react"; import type { PropsWithChildren } from "react"; import Link from "next/link"; +import { redirect } from "next/navigation"; import { AccordionControl, AccordionItem, @@ -50,11 +51,16 @@ interface IntegrationsPageProps { } export default async function IntegrationsPage({ searchParams }: IntegrationsPageProps) { - const integrations = await api.integration.all(); const session = await auth(); + + if (!session) { + redirect("/auth/login"); + } + + const integrations = await api.integration.all(); const t = await getScopedI18n("integration"); - const canCreateIntegrations = session?.user.permissions.includes("integration-create") ?? false; + const canCreateIntegrations = session.user.permissions.includes("integration-create"); return ( diff --git a/apps/nextjs/src/app/[locale]/manage/layout.tsx b/apps/nextjs/src/app/[locale]/manage/layout.tsx index f9a397e38..0613e46d6 100644 --- a/apps/nextjs/src/app/[locale]/manage/layout.tsx +++ b/apps/nextjs/src/app/[locale]/manage/layout.tsx @@ -52,16 +52,19 @@ export default async function ManageLayout({ children }: PropsWithChildren) { icon: IconBox, href: "/manage/apps", label: t("items.apps"), + hidden: !session, }, { icon: IconPlug, href: "/manage/integrations", label: t("items.integrations"), + hidden: !session, }, { icon: IconSearch, href: "/manage/search-engines", label: t("items.searchEngies"), + hidden: !session, }, { icon: IconPhoto, @@ -95,27 +98,32 @@ export default async function ManageLayout({ children }: PropsWithChildren) { { label: t("items.tools.label"), icon: IconTool, - hidden: !session?.user.permissions.includes("admin"), + // As permissions always include there children permissions, we can check other-view-logs as admin includes it + hidden: !session?.user.permissions.includes("other-view-logs"), items: [ { label: t("items.tools.items.docker"), icon: IconBrandDocker, href: "/manage/tools/docker", + hidden: !session?.user.permissions.includes("admin"), }, { label: t("items.tools.items.api"), icon: IconPlug, href: "/manage/tools/api", + hidden: !session?.user.permissions.includes("admin"), }, { label: t("items.tools.items.logs"), icon: IconLogs, href: "/manage/tools/logs", + hidden: !session?.user.permissions.includes("other-view-logs"), }, { label: t("items.tools.items.tasks"), icon: IconReport, href: "/manage/tools/tasks", + hidden: !session?.user.permissions.includes("admin"), }, ], }, diff --git a/apps/nextjs/src/app/[locale]/manage/medias/page.tsx b/apps/nextjs/src/app/[locale]/manage/medias/page.tsx index c46701935..5052194c9 100644 --- a/apps/nextjs/src/app/[locale]/manage/medias/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/medias/page.tsx @@ -47,7 +47,6 @@ export default async function GroupsListPage(props: MediaListPageProps) { const t = await getI18n(); const searchParams = searchParamsSchema.parse(props.searchParams); const { items: medias, totalCount } = await api.media.getPaginated(searchParams); - const isAdmin = session.user.permissions.includes("admin"); return ( @@ -57,10 +56,12 @@ export default async function GroupsListPage(props: MediaListPageProps) { - {isAdmin && } + {session.user.permissions.includes("media-view-all") && ( + + )} - + {session.user.permissions.includes("media-upload") && } @@ -91,7 +92,10 @@ interface RowProps { media: RouterOutputs["media"]["getPaginated"]["items"][number]; } -const Row = ({ media }: RowProps) => { +const Row = async ({ media }: RowProps) => { + const session = await auth(); + const canDelete = media.creatorId === session?.user.id || session?.user.permissions.includes("media-full-all"); + return ( @@ -120,7 +124,7 @@ const Row = ({ media }: RowProps) => { - + {canDelete && } diff --git a/apps/nextjs/src/app/[locale]/manage/page.tsx b/apps/nextjs/src/app/[locale]/manage/page.tsx index 31137d121..6d2b03880 100644 --- a/apps/nextjs/src/app/[locale]/manage/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/page.tsx @@ -64,6 +64,7 @@ export default async function ManagementPage() { href: "/manage/apps", subtitle: t("statisticLabel.resources"), title: t("statistic.app"), + hidden: !session?.user, }, { count: statistics.countGroups, diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx index a130fb4fa..39dfd8f63 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx @@ -1,6 +1,8 @@ +import { notFound } from "next/navigation"; import { Stack, Title } from "@mantine/core"; import { api } from "@homarr/api/server"; +import { auth } from "@homarr/auth/next"; import { getI18n } from "@homarr/translation/server"; import { ManageContainer } from "~/components/manage/manage-container"; @@ -12,6 +14,12 @@ interface SearchEngineEditPageProps { } export default async function SearchEngineEditPage({ params }: SearchEngineEditPageProps) { + const session = await auth(); + + if (!session?.user.permissions.includes("search-engine-modify-all")) { + notFound(); + } + const searchEngine = await api.searchEngine.byId({ id: params.id }); const t = await getI18n(); diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/new/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/new/page.tsx index fb1c51340..488f1c3af 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/new/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/new/page.tsx @@ -1,5 +1,7 @@ +import { notFound } from "next/navigation"; import { Stack, Title } from "@mantine/core"; +import { auth } from "@homarr/auth/next"; import { getI18n } from "@homarr/translation/server"; import { ManageContainer } from "~/components/manage/manage-container"; @@ -7,6 +9,12 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { SearchEngineNewForm } from "./_search-engine-new-form"; export default async function SearchEngineNewPage() { + const session = await auth(); + + if (!session?.user.permissions.includes("search-engine-create")) { + notFound(); + } + const t = await getI18n(); return ( diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx index 423c7fe9c..8f66abbf1 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx @@ -1,9 +1,11 @@ import Link from "next/link"; +import { redirect } from "next/navigation"; import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text, Title } from "@mantine/core"; import { IconPencil, IconSearch } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; +import { auth } from "@homarr/auth/next"; import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { SearchInput, TablePagination } from "@homarr/ui"; import { z } from "@homarr/validation"; @@ -28,6 +30,12 @@ interface SearchEnginesPageProps { } export default async function SearchEnginesPage(props: SearchEnginesPageProps) { + const session = await auth(); + + if (!session) { + redirect("/auth/login"); + } + const searchParams = searchParamsSchema.parse(props.searchParams); const { items: searchEngines, totalCount } = await api.searchEngine.getPaginated(searchParams); @@ -40,9 +48,11 @@ export default async function SearchEnginesPage(props: SearchEnginesPageProps) { {tEngine("page.list.title")} - - {tEngine("page.create.title")} - + {session.user.permissions.includes("search-engine-create") && ( + + {tEngine("page.create.title")} + + )} {searchEngines.length === 0 && } {searchEngines.length > 0 && ( @@ -67,6 +77,7 @@ interface SearchEngineCardProps { const SearchEngineCard = async ({ searchEngine }: SearchEngineCardProps) => { const t = await getScopedI18n("search.engine"); + const session = await auth(); return ( @@ -105,16 +116,20 @@ const SearchEngineCard = async ({ searchEngine }: SearchEngineCardProps) => { - - - - + {session?.user.permissions.includes("search-engine-modify-all") && ( + + + + )} + {session?.user.permissions.includes("search-engine-full-all") && ( + + )} @@ -124,6 +139,7 @@ const SearchEngineCard = async ({ searchEngine }: SearchEngineCardProps) => { const SearchEngineNoResults = async () => { const t = await getI18n(); + const session = await auth(); return ( @@ -132,7 +148,9 @@ const SearchEngineNoResults = async () => { {t("search.engine.page.list.noResults.title")} - {t("search.engine.page.list.noResults.action")} + {session?.user.permissions.includes("search-engine-create") && ( + {t("search.engine.page.list.noResults.action")} + )} ); diff --git a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx index 71a0efb1b..660a5597a 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx @@ -23,7 +23,7 @@ export const ApiKeysManagement = ({ apiKeys }: ApiKeysManagementProps) => { const { mutate, isPending } = clientApi.apiKeys.create.useMutation({ async onSuccess(data) { openModal({ - apiKey: data.randomToken, + apiKey: data.apiKey, }); await revalidatePathActionAsync("/manage/tools/api"); }, diff --git a/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx b/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx index 131ce7859..946238d3e 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx @@ -27,7 +27,7 @@ export async function generateMetadata() { export default async function LogsManagementPage() { const session = await auth(); - if (!session?.user || !session.user.permissions.includes("admin")) { + if (!session?.user || !session.user.permissions.includes("other-view-logs")) { notFound(); } diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx index ede4d8df9..e41d38536 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx @@ -8,7 +8,7 @@ import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { CurrentLanguageCombobox } from "~/components/language/current-language-combobox"; import { DangerZoneItem, DangerZoneRoot } from "~/components/manage/danger-zone"; -import { catchTrpcNotFound } from "~/errors/trpc-not-found"; +import { catchTrpcNotFound } from "~/errors/trpc-catch-error"; import { createMetaTitle } from "~/metadata"; import { canAccessUserEditPage } from "../access"; import { ChangeHomeBoardForm } from "./_components/_change-home-board"; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/layout.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/layout.tsx index 06bbbf5ee..c7158379d 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/layout.tsx @@ -10,7 +10,7 @@ import { UserAvatar } from "@homarr/ui"; import { ManageContainer } from "~/components/manage/manage-container"; import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; -import { catchTrpcNotFound } from "~/errors/trpc-not-found"; +import { catchTrpcNotFound } from "~/errors/trpc-catch-error"; import { NavigationLink } from "../groups/[id]/_navigation"; import { canAccessUserEditPage } from "./access"; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/page.tsx index 99061405d..9897268b2 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/page.tsx @@ -5,7 +5,7 @@ import { api } from "@homarr/api/server"; import { auth } from "@homarr/auth/next"; import { getScopedI18n } from "@homarr/translation/server"; -import { catchTrpcNotFound } from "~/errors/trpc-not-found"; +import { catchTrpcNotFound } from "~/errors/trpc-catch-error"; import { canAccessUserEditPage } from "../access"; import { ChangePasswordForm } from "./_components/_change-password-form"; diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx index a777ce73d..07d5dd55f 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx @@ -1,12 +1,14 @@ +"use client"; + import Link from "next/link"; import { Alert, Anchor } from "@mantine/core"; import { IconExclamationCircle } from "@tabler/icons-react"; import { createDocumentationLink } from "@homarr/definitions"; -import { getI18n } from "@homarr/translation/server"; +import { useI18n } from "@homarr/translation/client"; -export const ReservedGroupAlert = async () => { - const t = await getI18n(); +export const ReservedGroupAlert = () => { + const t = useI18n(); return ( }> diff --git a/apps/nextjs/src/app/api/[...trpc]/route.ts b/apps/nextjs/src/app/api/[...trpc]/route.ts index 669a2bd0c..1ac9fb77f 100644 --- a/apps/nextjs/src/app/api/[...trpc]/route.ts +++ b/apps/nextjs/src/app/api/[...trpc]/route.ts @@ -1,15 +1,21 @@ +import { headers } from "next/headers"; +import { userAgent } from "next/server"; +import type { NextRequest } from "next/server"; import { createOpenApiFetchHandler } from "trpc-swagger/build/index.mjs"; import { appRouter, createTRPCContext } from "@homarr/api"; +import { hashPasswordAsync } from "@homarr/auth"; import type { Session } from "@homarr/auth"; import { createSessionAsync } from "@homarr/auth/server"; import { db, eq } from "@homarr/db"; import { apiKeys } from "@homarr/db/schema/sqlite"; import { logger } from "@homarr/log"; -const handlerAsync = async (req: Request) => { +const handlerAsync = async (req: NextRequest) => { const apiKeyHeaderValue = req.headers.get("ApiKey"); - const session: Session | null = await getSessionOrDefaultFromHeadersAsync(apiKeyHeaderValue); + const ipAddress = req.ip ?? headers().get("x-forwarded-for"); + const { ua } = userAgent(req); + const session: Session | null = await getSessionOrDefaultFromHeadersAsync(apiKeyHeaderValue, ipAddress, ua); return createOpenApiFetchHandler({ req, @@ -19,7 +25,11 @@ const handlerAsync = async (req: Request) => { }); }; -const getSessionOrDefaultFromHeadersAsync = async (apiKeyHeaderValue: string | null): Promise => { +const getSessionOrDefaultFromHeadersAsync = async ( + apiKeyHeaderValue: string | null, + ipAdress: string | null, + userAgent: string, +): Promise => { logger.info( `Creating OpenAPI fetch handler for user ${apiKeyHeaderValue ? "with an api key" : "without an api key"}`, ); @@ -28,12 +38,21 @@ const getSessionOrDefaultFromHeadersAsync = async (apiKeyHeaderValue: string | n return null; } + const [apiKeyId, apiKey] = apiKeyHeaderValue.split("."); + + if (!apiKeyId || !apiKey) { + logger.warn( + `An attempt to authenticate over API has failed due to invalid API key format ip='${ipAdress}' userAgent='${userAgent}'`, + ); + return null; + } + const apiKeyFromDb = await db.query.apiKeys.findFirst({ - where: eq(apiKeys.apiKey, apiKeyHeaderValue), + where: eq(apiKeys.id, apiKeyId), columns: { id: true, - apiKey: false, - salt: false, + apiKey: true, + salt: true, }, with: { user: { @@ -47,8 +66,15 @@ const getSessionOrDefaultFromHeadersAsync = async (apiKeyHeaderValue: string | n }, }); - if (apiKeyFromDb === undefined) { - logger.warn("An attempt to authenticate over API has failed"); + if (!apiKeyFromDb) { + logger.warn(`An attempt to authenticate over API has failed ip='${ipAdress}' userAgent='${userAgent}'`); + return null; + } + + const hashedApiKey = await hashPasswordAsync(apiKey, apiKeyFromDb.salt); + + if (apiKeyFromDb.apiKey !== hashedApiKey) { + logger.warn(`An attempt to authenticate over API has failed ip='${ipAdress}' userAgent='${userAgent}'`); return null; } diff --git a/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts b/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts index 5c3fb207b..2d1a8987c 100644 --- a/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts +++ b/apps/nextjs/src/components/board/sections/gridstack/use-gridstack.ts @@ -71,15 +71,6 @@ export const useGridstack = (section: Omit, itemIds: string[]) ? section.width : board.columnCount; - useCssVariableConfiguration({ - columnCount, - gridRef, - wrapperRef, - width, - height, - isDynamic: section.kind === "dynamic", - }); - const itemRefKeys = Object.keys(itemRefs.current); // define items in itemRefs for easy access and reference to items if (itemRefKeys.length !== itemIds.length) { @@ -95,11 +86,6 @@ export const useGridstack = (section: Omit, itemIds: string[]) }); } - // Toggle the gridstack to be static or not based on the edit mode - useEffect(() => { - gridRef.current?.setStatic(!isEditMode); - }, [isEditMode]); - const onChange = useCallback( (changedNode: GridStackNode) => { const id = changedNode.el?.getAttribute("data-id"); @@ -258,14 +244,40 @@ export const useGridstack = (section: Omit, itemIds: string[]) }; }, [isEditMode, onAdd, onChange]); + /** + * IMPORTANT: This effect has to be placed after the effect to initialize the gridstack + * because we need the gridstack object to add the listeners + * Toggle the gridstack to be static or not based on the edit mode + */ + useEffect(() => { + gridRef.current?.setStatic(!isEditMode); + }, [isEditMode]); + const sectionHeight = section.kind === "dynamic" && "height" in section ? (section.height as number) : null; - // We want the amount of rows in a dynamic section to be the height of the section in the outer gridstack + /** + * IMPORTANT: This effect has to be placed after the effect to initialize the gridstack + * because we need the gridstack object to add the listeners + * We want the amount of rows in a dynamic section to be the height of the section in the outer gridstack + */ useEffect(() => { if (!sectionHeight) return; gridRef.current?.row(sectionHeight); }, [sectionHeight]); + /** + * IMPORTANT: This effect has to be placed after the effect to initialize the gridstack + * because we need the gridstack object to add the listeners + */ + useCssVariableConfiguration({ + columnCount, + gridRef, + wrapperRef, + width, + height, + isDynamic: section.kind === "dynamic", + }); + return { refs: { items: itemRefs, diff --git a/apps/nextjs/src/components/icons/picker/icon-picker.tsx b/apps/nextjs/src/components/icons/picker/icon-picker.tsx index 91983ff7c..bd77a27d5 100644 --- a/apps/nextjs/src/components/icons/picker/icon-picker.tsx +++ b/apps/nextjs/src/components/icons/picker/icon-picker.tsx @@ -1,9 +1,23 @@ import type { FocusEventHandler } from "react"; -import { useState } from "react"; -import { Combobox, Group, Image, InputBase, Skeleton, Text, useCombobox } from "@mantine/core"; +import { startTransition, useState } from "react"; +import { + Box, + Card, + Combobox, + Flex, + Image, + Indicator, + InputBase, + Paper, + Skeleton, + Stack, + Text, + UnstyledButton, + useCombobox, +} from "@mantine/core"; import { clientApi } from "@homarr/api/client"; -import { useI18n, useScopedI18n } from "@homarr/translation/client"; +import { useScopedI18n } from "@homarr/translation/client"; interface IconPickerProps { initialValue?: string; @@ -18,10 +32,9 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I const [search, setSearch] = useState(initialValue ?? ""); const [previewUrl, setPreviewUrl] = useState(initialValue ?? null); - const t = useI18n(); const tCommon = useScopedI18n("common"); - const { data, isFetching } = clientApi.icon.findIcons.useQuery({ + const [data] = clientApi.icon.findIcons.useSuspenseQuery({ searchText: search, }); @@ -29,39 +42,53 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I onDropdownClose: () => combobox.resetSelectedOption(), }); - const notNullableData = data?.icons ?? []; - - const totalOptions = notNullableData.reduce((acc, group) => acc + group.icons.length, 0); - - const groups = notNullableData.map((group) => { + const totalOptions = data.icons.reduce((acc, group) => acc + group.icons.length, 0); + const groups = data.icons.map((group) => { const options = group.icons.map((item) => ( - - - - {item.name} - - + { + const value = item.url; + startTransition(() => { + setValue(value); + setPreviewUrl(value); + setSearch(value); + onChange(value); + combobox.closeDropdown(); + }); + }} + key={item.id} + > + + + + + + + + )); return ( - - {options} - + + + {group.slug} + + + {options} + + ); }); return ( - { - setValue(value); - setPreviewUrl(value); - setSearch(value); - onChange(value); - combobox.closeDropdown(); - }} - store={combobox} - withinPortal - > + } @@ -91,18 +118,14 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I withAsterisk error={error} label={tCommon("iconPicker.label")} + placeholder={tCommon("iconPicker.header", { countIcons: data.countIcons })} /> - - {tCommon("iconPicker.header", { countIcons: data?.countIcons })} - {totalOptions > 0 ? ( - groups - ) : !isFetching ? ( - {t("search.nothingFound")} + {groups} ) : ( Array(15) .fill(0) diff --git a/apps/nextjs/src/errors/trpc-catch-error.ts b/apps/nextjs/src/errors/trpc-catch-error.ts new file mode 100644 index 000000000..1fb766745 --- /dev/null +++ b/apps/nextjs/src/errors/trpc-catch-error.ts @@ -0,0 +1,23 @@ +import "server-only"; + +import { notFound, redirect } from "next/navigation"; +import { TRPCError } from "@trpc/server"; + +import { logger } from "@homarr/log"; + +export const catchTrpcNotFound = (err: unknown) => { + if (err instanceof TRPCError && err.code === "NOT_FOUND") { + notFound(); + } + + throw err; +}; + +export const catchTrpcUnauthorized = (err: unknown) => { + if (err instanceof TRPCError && err.code === "UNAUTHORIZED") { + logger.info("Somebody tried to access a protected route without being authenticated, redirecting to login page"); + redirect("/auth/login"); + } + + throw err; +}; diff --git a/apps/nextjs/src/errors/trpc-not-found.ts b/apps/nextjs/src/errors/trpc-not-found.ts deleted file mode 100644 index 3ae693203..000000000 --- a/apps/nextjs/src/errors/trpc-not-found.ts +++ /dev/null @@ -1,12 +0,0 @@ -import "server-only"; - -import { notFound } from "next/navigation"; -import { TRPCError } from "@trpc/server"; - -export const catchTrpcNotFound = (err: unknown) => { - if (err instanceof TRPCError && err.code === "NOT_FOUND") { - notFound(); - } - - throw err; -}; diff --git a/apps/tasks/package.json b/apps/tasks/package.json index a84753faf..c2b7cfb8b 100644 --- a/apps/tasks/package.json +++ b/apps/tasks/package.json @@ -44,9 +44,9 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/node": "^22.9.0", - "dotenv-cli": "^7.4.2", - "eslint": "^9.14.0", + "@types/node": "^22.9.1", + "dotenv-cli": "^7.4.4", + "eslint": "^9.15.0", "prettier": "^3.3.3", "tsx": "4.19.2", "typescript": "^5.6.3" diff --git a/apps/tasks/src/test/undici-log-agent-override.spec.ts b/apps/tasks/src/test/undici-log-agent-override.spec.ts new file mode 100644 index 000000000..d5d2af1f6 --- /dev/null +++ b/apps/tasks/src/test/undici-log-agent-override.spec.ts @@ -0,0 +1,99 @@ +import type { Dispatcher } from "undici"; +import { describe, expect, test, vi } from "vitest"; + +import { logger } from "@homarr/log"; + +import { LoggingAgent } from "~/undici-log-agent-override"; + +vi.mock("undici", () => { + return { + Agent: class Agent { + dispatch(_options: Dispatcher.DispatchOptions, _handler: Dispatcher.DispatchHandlers): boolean { + return true; + } + }, + setGlobalDispatcher: () => undefined, + }; +}); + +const REDACTED = "REDACTED"; + +describe("LoggingAgent should log all requests", () => { + test("should log all requests", () => { + // Arrange + const infoLogSpy = vi.spyOn(logger, "info"); + const agent = new LoggingAgent(); + + // Act + agent.dispatch({ origin: "https://homarr.dev", path: "/", method: "GET" }, {}); + + // Assert + expect(infoLogSpy).toHaveBeenCalledWith("Dispatching request https://homarr.dev/ (0 headers)"); + }); + + test("should show amount of headers", () => { + // Arrange + const infoLogSpy = vi.spyOn(logger, "info"); + const agent = new LoggingAgent(); + + // Act + agent.dispatch( + { + origin: "https://homarr.dev", + path: "/", + method: "GET", + headers: { + "Content-Type": "text/html", + "User-Agent": "Mozilla/5.0", + }, + }, + {}, + ); + + // Assert + expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining("(2 headers)")); + }); + + test.each([ + ["/?hex=a3815e8ada2ef9a31", `/?hex=${REDACTED}`], + ["/?uuid=f7c3f65e-c511-4f90-ba9a-3fd31418bd49", `/?uuid=${REDACTED}`], + ["/?password=complexPassword123", `/?password=${REDACTED}`], + [ + // JWT for John Doe + "/?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + `/?jwt=${REDACTED}`, + ], + ["/?one=a1&two=b2&three=c3", `/?one=${REDACTED}&two=${REDACTED}&three=${REDACTED}`], + ["/?numberWith13Chars=1234567890123", `/?numberWith13Chars=${REDACTED}`], + [`/?stringWith13Chars=${"a".repeat(13)}`, `/?stringWith13Chars=${REDACTED}`], + ])("should redact sensitive data in url https://homarr.dev%s", (path, expected) => { + // Arrange + const infoLogSpy = vi.spyOn(logger, "info"); + const agent = new LoggingAgent(); + + // Act + agent.dispatch({ origin: "https://homarr.dev", path, method: "GET" }, {}); + + // Assert + expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining(` https://homarr.dev${expected} `)); + }); + test.each([ + ["empty", "/?empty"], + ["numbers with max 12 chars", "/?number=123456789012"], + ["true", "/?true=true"], + ["false", "/?false=false"], + ["strings with max 12 chars", `/?short=${"a".repeat(12)}`], + ["dates", "/?date=2022-01-01"], + ["date times", "/?datetime=2022-01-01T00:00:00.000Z"], + ])("should not redact values that are %s", (_reason, path) => { + // Arrange + const infoLogSpy = vi.spyOn(logger, "info"); + const agent = new LoggingAgent(); + + // Act + agent.dispatch({ origin: "https://homarr.dev", path, method: "GET" }, {}); + + // Assert + expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining(` https://homarr.dev${path} `)); + }); +}); diff --git a/apps/tasks/src/undici-log-agent-override.ts b/apps/tasks/src/undici-log-agent-override.ts index 79d443e86..6f02985c0 100644 --- a/apps/tasks/src/undici-log-agent-override.ts +++ b/apps/tasks/src/undici-log-agent-override.ts @@ -3,7 +3,7 @@ import { Agent, setGlobalDispatcher } from "undici"; import { logger } from "@homarr/log"; -class LoggingAgent extends Agent { +export class LoggingAgent extends Agent { constructor(...props: ConstructorParameters) { super(...props); } @@ -15,15 +15,17 @@ class LoggingAgent extends Agent { // some integrations use query parameters for auth url.searchParams.forEach((value, key) => { if (value === "") return; // Skip empty values - if (/^\d{1,12}$/.test(value)) return; // Skip small numbers + if (/^-?\d{1,12}$/.test(value)) return; // Skip small numbers if (value === "true" || value === "false") return; // Skip boolean values if (/^[a-zA-Z]{1,12}$/.test(value)) return; // Skip short strings + if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return; // Skip dates + if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) return; // Skip date times url.searchParams.set(key, "REDACTED"); }); logger.info( - `Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers as object).length} headers)`, + `Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers ?? {}).length} headers)`, ); return super.dispatch(options, handler); } diff --git a/apps/websocket/package.json b/apps/websocket/package.json index 8de047bad..d1113bc21 100644 --- a/apps/websocket/package.json +++ b/apps/websocket/package.json @@ -34,7 +34,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/ws": "^8.5.13", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/package.json b/package.json index ca64b04ac..aa6d89119 100644 --- a/package.json +++ b/package.json @@ -28,20 +28,20 @@ "prettier": "@homarr/prettier-config", "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", - "@turbo/gen": "^2.3.0", + "@turbo/gen": "^2.3.1", "@vitejs/plugin-react": "^4.3.3", "@vitest/coverage-v8": "^2.1.5", "@vitest/ui": "^2.1.5", "cross-env": "^7.0.3", "jsdom": "^25.0.1", "prettier": "^3.3.3", - "testcontainers": "^10.14.0", - "turbo": "^2.3.0", + "testcontainers": "^10.15.0", + "turbo": "^2.3.1", "typescript": "^5.6.3", - "vite-tsconfig-paths": "^5.1.2", + "vite-tsconfig-paths": "^5.1.3", "vitest": "^2.1.5" }, - "packageManager": "pnpm@9.13.2", + "packageManager": "pnpm@9.14.2", "engines": { "node": ">=22.11.0" }, diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 1913ea60c..67cfe4b71 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -32,7 +32,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/api/package.json b/packages/api/package.json index dfc68eb94..9bbb3cb1b 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -48,8 +48,8 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/dockerode": "^3.3.31", - "eslint": "^9.14.0", + "@types/dockerode": "^3.3.32", + "eslint": "^9.15.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/packages/api/src/client.ts b/packages/api/src/client.ts index 0d7c95f38..b40cdd412 100644 --- a/packages/api/src/client.ts +++ b/packages/api/src/client.ts @@ -7,13 +7,9 @@ export const clientApi = createTRPCReact(); export const fetchApi = createTRPCClient({ links: [ httpLink({ - url: `${getBaseUrl()}/api/trpc`, + url: getTrpcUrl(), transformer: SuperJSON, - headers() { - const headers = new Headers(); - headers.set("x-trpc-source", "fetch"); - return headers; - }, + headers: createHeadersCallbackForSource("fetch"), }), ], }); @@ -23,3 +19,50 @@ function getBaseUrl() { if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; return `http://localhost:${process.env.PORT ?? 3000}`; } + +/** + * Creates the full url for the trpc api endpoint + * @returns + */ +export function getTrpcUrl() { + return `${getBaseUrl()}/api/trpc`; +} + +/** + * Creates a headers callback for a given source + * It will set the x-trpc-source header and cookies if needed + * @param source trpc source request comes from + * @returns headers callback + */ +export function createHeadersCallbackForSource(source: string) { + return async () => { + const headers = new Headers(); + headers.set("x-trpc-source", source); + + const cookies = await importCookiesAsync(); + // We need to set cookie for ssr requests (for example with useSuspenseQuery or middleware) + if (cookies) { + headers.set("cookie", cookies); + } + + return headers; + }; +} + +/** + * This is a workarround as cookies are not passed to the server + * when using useSuspenseQuery or middleware + * @returns cookie string on server or null on client + */ +async function importCookiesAsync() { + if (typeof window === "undefined") { + return await import("next/headers").then(({ cookies }) => + cookies() + .getAll() + .map(({ name, value }) => `${name}=${value}`) + .join(";"), + ); + } + + return null; +} diff --git a/packages/api/src/router/apiKeys.ts b/packages/api/src/router/apiKeys.ts index df5fd85d0..715e85906 100644 --- a/packages/api/src/router/apiKeys.ts +++ b/packages/api/src/router/apiKeys.ts @@ -28,14 +28,15 @@ export const apiKeysRouter = createTRPCRouter({ const salt = await createSaltAsync(); const randomToken = generateSecureRandomToken(64); const hashedRandomToken = await hashPasswordAsync(randomToken, salt); + const id = createId(); await db.insert(apiKeys).values({ - id: createId(), + id, apiKey: hashedRandomToken, salt, userId: ctx.session.user.id, }); return { - randomToken, + apiKey: `${id}.${randomToken}`, }; }), }); diff --git a/packages/api/src/router/app.ts b/packages/api/src/router/app.ts index 1ce137b72..62e3f2674 100644 --- a/packages/api/src/router/app.ts +++ b/packages/api/src/router/app.ts @@ -4,10 +4,11 @@ import { asc, createId, eq, inArray, like } from "@homarr/db"; import { apps } from "@homarr/db/schema/sqlite"; import { validation, z } from "@homarr/validation"; -import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc"; +import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; +import { canUserSeeAppAsync } from "./app/app-access-control"; export const appRouter = createTRPCRouter({ - all: publicProcedure + all: protectedProcedure .input(z.void()) .output( z.array( @@ -26,7 +27,7 @@ export const appRouter = createTRPCRouter({ orderBy: asc(apps.name), }); }), - search: publicProcedure + search: protectedProcedure .input(z.object({ query: z.string(), limit: z.number().min(1).max(100).default(10) })) .output( z.array( @@ -47,7 +48,7 @@ export const appRouter = createTRPCRouter({ limit: input.limit, }); }), - selectable: publicProcedure + selectable: protectedProcedure .input(z.void()) .output( z.array( @@ -104,14 +105,23 @@ export const appRouter = createTRPCRouter({ }); } + const canUserSeeApp = await canUserSeeAppAsync(ctx.session?.user ?? null, app.id); + if (!canUserSeeApp) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "App not found", + }); + } + return app; }), - byIds: publicProcedure.input(z.array(z.string())).query(async ({ ctx, input }) => { + byIds: protectedProcedure.input(z.array(z.string())).query(async ({ ctx, input }) => { return await ctx.db.query.apps.findMany({ where: inArray(apps.id, input), }); }), - create: protectedProcedure + create: permissionRequiredProcedure + .requiresPermission("app-create") .input(validation.app.manage) .output(z.void()) .meta({ openapi: { method: "POST", path: "/api/apps", tags: ["apps"], protect: true } }) @@ -124,29 +134,33 @@ export const appRouter = createTRPCRouter({ href: input.href, }); }), - update: protectedProcedure.input(validation.app.edit).mutation(async ({ ctx, input }) => { - const app = await ctx.db.query.apps.findFirst({ - where: eq(apps.id, input.id), - }); - - if (!app) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "App not found", + update: permissionRequiredProcedure + .requiresPermission("app-modify-all") + .input(validation.app.edit) + .mutation(async ({ ctx, input }) => { + const app = await ctx.db.query.apps.findFirst({ + where: eq(apps.id, input.id), }); - } - await ctx.db - .update(apps) - .set({ - name: input.name, - description: input.description, - iconUrl: input.iconUrl, - href: input.href, - }) - .where(eq(apps.id, input.id)); - }), - delete: protectedProcedure + if (!app) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "App not found", + }); + } + + await ctx.db + .update(apps) + .set({ + name: input.name, + description: input.description, + iconUrl: input.iconUrl, + href: input.href, + }) + .where(eq(apps.id, input.id)); + }), + delete: permissionRequiredProcedure + .requiresPermission("app-full-all") .output(z.void()) .meta({ openapi: { method: "DELETE", path: "/api/apps/{id}", tags: ["apps"], protect: true } }) .input(validation.common.byId) diff --git a/packages/api/src/router/app/app-access-control.ts b/packages/api/src/router/app/app-access-control.ts new file mode 100644 index 000000000..b395cea09 --- /dev/null +++ b/packages/api/src/router/app/app-access-control.ts @@ -0,0 +1,50 @@ +import SuperJSON from "superjson"; + +import type { Session } from "@homarr/auth"; +import { db, eq, or } from "@homarr/db"; +import { items } from "@homarr/db/schema/sqlite"; + +import type { WidgetComponentProps } from "../../../../widgets/src"; + +export const canUserSeeAppAsync = async (user: Session["user"] | null, appId: string) => { + return await canUserSeeAppsAsync(user, [appId]); +}; + +export const canUserSeeAppsAsync = async (user: Session["user"] | null, appIds: string[]) => { + if (user) return true; + + const appIdsOnPublicBoards = await getAllAppIdsOnPublicBoardsAsync(); + return appIds.every((appId) => appIdsOnPublicBoards.includes(appId)); +}; + +const getAllAppIdsOnPublicBoardsAsync = async () => { + const itemsWithApps = await db.query.items.findMany({ + where: or(eq(items.kind, "app"), eq(items.kind, "bookmarks")), + with: { + section: { + columns: {}, // Nothing + with: { + board: { + columns: { + isPublic: true, + }, + }, + }, + }, + }, + }); + + return itemsWithApps + .filter((item) => item.section.board.isPublic) + .flatMap((item) => { + if (item.kind === "app") { + const parsedOptions = SuperJSON.parse["options"]>(item.options); + return [parsedOptions.appId]; + } else if (item.kind === "bookmarks") { + const parsedOptions = SuperJSON.parse["options"]>(item.options); + return parsedOptions.items; + } + + throw new Error("Failed to get app ids from board. Invalid item kind: 'test'"); + }); +}; diff --git a/packages/api/src/router/icons.ts b/packages/api/src/router/icons.ts index e99918da3..7b7c2f52b 100644 --- a/packages/api/src/router/icons.ts +++ b/packages/api/src/router/icons.ts @@ -16,7 +16,7 @@ export const iconsRouter = createTRPCRouter({ url: true, }, where: (input.searchText?.length ?? 0) > 0 ? like(icons.name, `%${input.searchText}%`) : undefined, - limit: 5, + limit: input.limitPerGroup, }, }, }), diff --git a/packages/api/src/router/integration/integration-test-connection.ts b/packages/api/src/router/integration/integration-test-connection.ts index 91d12f344..93a0bc356 100644 --- a/packages/api/src/router/integration/integration-test-connection.ts +++ b/packages/api/src/router/integration/integration-test-connection.ts @@ -52,7 +52,6 @@ export const testConnectionAsync = async ( const { secrets: _, ...baseIntegration } = integration; - // @ts-expect-error - For now we expect an error here as not all integrations have been implemented const integrationInstance = integrationCreator({ ...baseIntegration, decryptedSecrets, diff --git a/packages/api/src/router/log.ts b/packages/api/src/router/log.ts index d48196a19..f6794db13 100644 --- a/packages/api/src/router/log.ts +++ b/packages/api/src/router/log.ts @@ -7,7 +7,7 @@ import { loggingChannel } from "@homarr/redis"; import { createTRPCRouter, permissionRequiredProcedure } from "../trpc"; export const logRouter = createTRPCRouter({ - subscribe: permissionRequiredProcedure.requiresPermission("admin").subscription(() => { + subscribe: permissionRequiredProcedure.requiresPermission("other-view-logs").subscription(() => { return observable((emit) => { const unsubscribe = loggingChannel.subscribe((data) => { emit.next(data); diff --git a/packages/api/src/router/medias/media-router.ts b/packages/api/src/router/medias/media-router.ts index ebf8d256c..90f497523 100644 --- a/packages/api/src/router/medias/media-router.ts +++ b/packages/api/src/router/medias/media-router.ts @@ -4,7 +4,7 @@ import { and, createId, desc, eq, like } from "@homarr/db"; import { medias } from "@homarr/db/schema/sqlite"; import { validation, z } from "@homarr/validation"; -import { createTRPCRouter, protectedProcedure } from "../../trpc"; +import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../../trpc"; export const mediaRouter = createTRPCRouter({ getPaginated: protectedProcedure @@ -14,7 +14,7 @@ export const mediaRouter = createTRPCRouter({ ), ) .query(async ({ ctx, input }) => { - const includeFromAllUsers = ctx.session.user.permissions.includes("admin") && input.includeFromAllUsers; + const includeFromAllUsers = ctx.session.user.permissions.includes("media-view-all") && input.includeFromAllUsers; const where = and( input.search.length >= 1 ? like(medias.name, `%${input.search}%`) : undefined, @@ -46,20 +46,23 @@ export const mediaRouter = createTRPCRouter({ totalCount, }; }), - uploadMedia: protectedProcedure.input(validation.media.uploadMedia).mutation(async ({ ctx, input }) => { - const content = Buffer.from(await input.file.arrayBuffer()); - const id = createId(); - await ctx.db.insert(medias).values({ - id, - creatorId: ctx.session.user.id, - content, - size: input.file.size, - contentType: input.file.type, - name: input.file.name, - }); + uploadMedia: permissionRequiredProcedure + .requiresPermission("media-upload") + .input(validation.media.uploadMedia) + .mutation(async ({ ctx, input }) => { + const content = Buffer.from(await input.file.arrayBuffer()); + const id = createId(); + await ctx.db.insert(medias).values({ + id, + creatorId: ctx.session.user.id, + content, + size: input.file.size, + contentType: input.file.type, + name: input.file.name, + }); - return id; - }), + return id; + }), deleteMedia: protectedProcedure.input(validation.common.byId).mutation(async ({ ctx, input }) => { const dbMedia = await ctx.db.query.medias.findFirst({ where: eq(medias.id, input.id), @@ -75,8 +78,8 @@ export const mediaRouter = createTRPCRouter({ }); } - // Only allow admins and the creator of the media to delete it - if (!ctx.session.user.permissions.includes("admin") && ctx.session.user.id !== dbMedia.creatorId) { + // Only allow users with media-full-all permission and the creator of the media to delete it + if (!ctx.session.user.permissions.includes("media-full-all") && ctx.session.user.id !== dbMedia.creatorId) { throw new TRPCError({ code: "FORBIDDEN", message: "You don't have permission to delete this media", diff --git a/packages/api/src/router/search-engine/search-engine-router.ts b/packages/api/src/router/search-engine/search-engine-router.ts index 2bc1584b6..63c7c3bda 100644 --- a/packages/api/src/router/search-engine/search-engine-router.ts +++ b/packages/api/src/router/search-engine/search-engine-router.ts @@ -4,7 +4,7 @@ import { createId, eq, like, sql } from "@homarr/db"; import { searchEngines } from "@homarr/db/schema/sqlite"; import { validation } from "@homarr/validation"; -import { createTRPCRouter, protectedProcedure } from "../../trpc"; +import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../../trpc"; export const searchEngineRouter = createTRPCRouter({ getPaginated: protectedProcedure.input(validation.common.paginated).query(async ({ input, ctx }) => { @@ -59,43 +59,52 @@ export const searchEngineRouter = createTRPCRouter({ limit: input.limit, }); }), - create: protectedProcedure.input(validation.searchEngine.manage).mutation(async ({ ctx, input }) => { - await ctx.db.insert(searchEngines).values({ - id: createId(), - name: input.name, - short: input.short.toLowerCase(), - iconUrl: input.iconUrl, - urlTemplate: "urlTemplate" in input ? input.urlTemplate : null, - description: input.description, - type: input.type, - integrationId: "integrationId" in input ? input.integrationId : null, - }); - }), - update: protectedProcedure.input(validation.searchEngine.edit).mutation(async ({ ctx, input }) => { - const searchEngine = await ctx.db.query.searchEngines.findFirst({ - where: eq(searchEngines.id, input.id), - }); - - if (!searchEngine) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Search engine not found", - }); - } - - await ctx.db - .update(searchEngines) - .set({ + create: permissionRequiredProcedure + .requiresPermission("search-engine-create") + .input(validation.searchEngine.manage) + .mutation(async ({ ctx, input }) => { + await ctx.db.insert(searchEngines).values({ + id: createId(), name: input.name, + short: input.short.toLowerCase(), iconUrl: input.iconUrl, urlTemplate: "urlTemplate" in input ? input.urlTemplate : null, description: input.description, - integrationId: "integrationId" in input ? input.integrationId : null, type: input.type, - }) - .where(eq(searchEngines.id, input.id)); - }), - delete: protectedProcedure.input(validation.common.byId).mutation(async ({ ctx, input }) => { - await ctx.db.delete(searchEngines).where(eq(searchEngines.id, input.id)); - }), + integrationId: "integrationId" in input ? input.integrationId : null, + }); + }), + update: permissionRequiredProcedure + .requiresPermission("search-engine-modify-all") + .input(validation.searchEngine.edit) + .mutation(async ({ ctx, input }) => { + const searchEngine = await ctx.db.query.searchEngines.findFirst({ + where: eq(searchEngines.id, input.id), + }); + + if (!searchEngine) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Search engine not found", + }); + } + + await ctx.db + .update(searchEngines) + .set({ + name: input.name, + iconUrl: input.iconUrl, + urlTemplate: "urlTemplate" in input ? input.urlTemplate : null, + description: input.description, + integrationId: "integrationId" in input ? input.integrationId : null, + type: input.type, + }) + .where(eq(searchEngines.id, input.id)); + }), + delete: permissionRequiredProcedure + .requiresPermission("search-engine-full-all") + .input(validation.common.byId) + .mutation(async ({ ctx, input }) => { + await ctx.db.delete(searchEngines).where(eq(searchEngines.id, input.id)); + }), }); diff --git a/packages/api/src/router/test/app.spec.ts b/packages/api/src/router/test/app.spec.ts index 4fdb07d56..0354ad74e 100644 --- a/packages/api/src/router/test/app.spec.ts +++ b/packages/api/src/router/test/app.spec.ts @@ -5,23 +5,26 @@ import type { Session } from "@homarr/auth"; import { createId } from "@homarr/db"; import { apps } from "@homarr/db/schema/sqlite"; import { createDb } from "@homarr/db/test"; +import type { GroupPermissionKey } from "@homarr/definitions"; import { appRouter } from "../app"; +import * as appAccessControl from "../app/app-access-control"; // Mock the auth module to return an empty session vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session })); -const defaultSession: Session = { - user: { id: createId(), permissions: [], colorScheme: "light" }, +const createDefaultSession = (permissions: GroupPermissionKey[] = []): Session => ({ + user: { id: createId(), permissions, colorScheme: "light" }, expires: new Date().toISOString(), -}; +}); describe("all should return all apps", () => { - test("should return all apps", async () => { + test("should return all apps with session", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: null, + session: createDefaultSession(), }); await db.insert(apps).values([ @@ -48,15 +51,30 @@ describe("all should return all apps", () => { expect(result[1]!.href).toBeNull(); expect(result[1]!.description).toBeNull(); }); + test("should throw UNAUTHORIZED if the user is not authenticated", async () => { + // Arrange + const caller = appRouter.createCaller({ + db: createDb(), + session: null, + }); + + // Act + const actAsync = async () => await caller.all(); + + // Assert + await expect(actAsync()).rejects.toThrow("UNAUTHORIZED"); + }); }); describe("byId should return an app by id", () => { - test("should return an app by id", async () => { + test("should return an app by id when canUserSeeAppAsync returns true", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, session: null, }); + vi.spyOn(appAccessControl, "canUserSeeAppAsync").mockReturnValue(Promise.resolve(true)); await db.insert(apps).values([ { @@ -73,28 +91,61 @@ describe("byId should return an app by id", () => { }, ]); + // Act const result = await caller.byId({ id: "2" }); + + // Assert expect(result.name).toBe("Mantine"); }); + test("should throw NOT_FOUND error when canUserSeeAppAsync returns false", async () => { + // Arrange + const db = createDb(); + const caller = appRouter.createCaller({ + db, + session: null, + }); + await db.insert(apps).values([ + { + id: "2", + name: "Mantine", + description: "React components and hooks library", + iconUrl: "https://mantine.dev/favicon.svg", + href: "https://mantine.dev", + }, + ]); + vi.spyOn(appAccessControl, "canUserSeeAppAsync").mockReturnValue(Promise.resolve(false)); + + // Act + const actAsync = async () => await caller.byId({ id: "2" }); + + // Assert + await expect(actAsync()).rejects.toThrow("App not found"); + }); + test("should throw an error if the app does not exist", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, session: null, }); + // Act const actAsync = async () => await caller.byId({ id: "2" }); + + // Assert await expect(actAsync()).rejects.toThrow("App not found"); }); }); describe("create should create a new app with all arguments", () => { test("should create a new app", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: defaultSession, + session: createDefaultSession(["app-create"]), }); const input = { name: "Mantine", @@ -103,8 +154,10 @@ describe("create should create a new app with all arguments", () => { href: "https://mantine.dev", }; + // Act await caller.create(input); + // Assert const dbApp = await db.query.apps.findFirst(); expect(dbApp).toBeDefined(); expect(dbApp!.name).toBe(input.name); @@ -114,10 +167,11 @@ describe("create should create a new app with all arguments", () => { }); test("should create a new app only with required arguments", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: defaultSession, + session: createDefaultSession(["app-create"]), }); const input = { name: "Mantine", @@ -126,8 +180,10 @@ describe("create should create a new app with all arguments", () => { href: null, }; + // Act await caller.create(input); + // Assert const dbApp = await db.query.apps.findFirst(); expect(dbApp).toBeDefined(); expect(dbApp!.name).toBe(input.name); @@ -139,10 +195,11 @@ describe("create should create a new app with all arguments", () => { describe("update should update an app", () => { test("should update an app", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: defaultSession, + session: createDefaultSession(["app-modify-all"]), }); const appId = createId(); @@ -162,8 +219,10 @@ describe("update should update an app", () => { href: "https://mantine.dev", }; + // Act await caller.update(input); + // Assert const dbApp = await db.query.apps.findFirst(); expect(dbApp).toBeDefined(); @@ -174,12 +233,14 @@ describe("update should update an app", () => { }); test("should throw an error if the app does not exist", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: defaultSession, + session: createDefaultSession(["app-modify-all"]), }); + // Act const actAsync = async () => await caller.update({ id: createId(), @@ -188,16 +249,19 @@ describe("update should update an app", () => { description: null, href: null, }); + + // Assert await expect(actAsync()).rejects.toThrow("App not found"); }); }); describe("delete should delete an app", () => { test("should delete an app", async () => { + // Arrange const db = createDb(); const caller = appRouter.createCaller({ db, - session: defaultSession, + session: createDefaultSession(["app-full-all"]), }); const appId = createId(); @@ -207,8 +271,10 @@ describe("delete should delete an app", () => { iconUrl: "https://mantine.dev/favicon.svg", }); + // Act await caller.delete({ id: appId }); + // Assert const dbApp = await db.query.apps.findFirst(); expect(dbApp).toBeUndefined(); }); diff --git a/packages/auth/package.json b/packages/auth/package.json index 738d6157b..e6201a1a2 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -23,8 +23,8 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@auth/core": "^0.37.3", - "@auth/drizzle-adapter": "^1.7.3", + "@auth/core": "^0.37.4", + "@auth/drizzle-adapter": "^1.7.4", "@homarr/common": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", @@ -45,7 +45,7 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/bcrypt": "5.0.2", "@types/cookies": "0.9.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/packages/cli/package.json b/packages/cli/package.json index 565f3c414..ebb2b83b4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/common/package.json b/packages/common/package.json index 56096cbb6..784febf48 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -29,13 +29,13 @@ "dayjs": "^1.11.13", "next": "^14.2.18", "react": "^18.3.1", - "tldts": "^6.1.61" + "tldts": "^6.1.63" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-job-runner/package.json b/packages/cron-job-runner/package.json index 99e91bf1e..d26cdbb7a 100644 --- a/packages/cron-job-runner/package.json +++ b/packages/cron-job-runner/package.json @@ -30,7 +30,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-job-status/package.json b/packages/cron-job-status/package.json index a3357a408..c8ececd0b 100644 --- a/packages/cron-job-status/package.json +++ b/packages/cron-job-status/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-jobs-core/package.json b/packages/cron-jobs-core/package.json index 4d794bae0..c28c56ca2 100644 --- a/packages/cron-jobs-core/package.json +++ b/packages/cron-jobs-core/package.json @@ -32,7 +32,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/node-cron": "^3.0.11", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-jobs-core/src/creator.ts b/packages/cron-jobs-core/src/creator.ts index 62607377e..a25535db6 100644 --- a/packages/cron-jobs-core/src/creator.ts +++ b/packages/cron-jobs-core/src/creator.ts @@ -49,14 +49,17 @@ const createCallback = void catchingCallbackAsync(), { - scheduled: false, - name, - timezone: creatorOptions.timezone, - }); - creatorOptions.logger.logDebug( - `The cron job '${name}' was created with expression ${cronExpression} in timezone ${creatorOptions.timezone} and runOnStart ${options.runOnStart}`, - ); + let scheduledTask: cron.ScheduledTask | null = null; + if (cronExpression !== "never") { + scheduledTask = cron.schedule(cronExpression, () => void catchingCallbackAsync(), { + scheduled: false, + name, + timezone: creatorOptions.timezone, + }); + creatorOptions.logger.logDebug( + `The cron job '${name}' was created with expression ${cronExpression} in timezone ${creatorOptions.timezone} and runOnStart ${options.runOnStart}`, + ); + } return { name, @@ -90,7 +93,7 @@ export const createCronJobCreator = ( options: CreateCronJobOptions = { runOnStart: false }, ) => { creatorOptions.logger.logDebug(`Validating cron expression '${cronExpression}' for job: ${name}`); - if (!cron.validate(cronExpression)) { + if (cronExpression !== "never" && !cron.validate(cronExpression)) { throw new Error(`Invalid cron expression '${cronExpression}' for job '${name}'`); } creatorOptions.logger.logDebug(`Cron job expression '${cronExpression}' for job ${name} is valid`); @@ -102,6 +105,8 @@ export const createCronJobCreator = ( // This is a type guard to check if the cron expression is valid and give the user a type hint return returnValue as unknown as ValidateCron extends true ? typeof returnValue - : "Invalid cron expression"; + : TExpression extends "never" + ? typeof returnValue + : "Invalid cron expression"; }; }; diff --git a/packages/cron-jobs-core/src/expressions.ts b/packages/cron-jobs-core/src/expressions.ts index d3b187190..e8015b486 100644 --- a/packages/cron-jobs-core/src/expressions.ts +++ b/packages/cron-jobs-core/src/expressions.ts @@ -7,3 +7,4 @@ export const EVERY_10_MINUTES = checkCron("*/10 * * * *") satisfies string; export const EVERY_HOUR = checkCron("0 * * * *") satisfies string; export const EVERY_DAY = checkCron("0 0 * * */1") satisfies string; export const EVERY_WEEK = checkCron("0 0 * * 1") satisfies string; +export const NEVER = "never"; diff --git a/packages/cron-jobs-core/src/group.ts b/packages/cron-jobs-core/src/group.ts index 76dd1c765..af68ed566 100644 --- a/packages/cron-jobs-core/src/group.ts +++ b/packages/cron-jobs-core/src/group.ts @@ -34,13 +34,13 @@ export const createJobGroupCreator = ( options.logger.logInfo(`Starting schedule cron job ${job.name}.`); await job.onStartAsync(); - job.scheduledTask.start(); + job.scheduledTask?.start(); }, startAllAsync: async () => { for (const job of jobRegistry.values()) { options.logger.logInfo(`Starting schedule of cron job ${job.name}.`); await job.onStartAsync(); - job.scheduledTask.start(); + job.scheduledTask?.start(); } }, runManually: (name: keyof TJobs) => { @@ -48,19 +48,19 @@ export const createJobGroupCreator = ( if (!job) return; options.logger.logInfo(`Running schedule cron job ${job.name} manually.`); - job.scheduledTask.now(); + job.scheduledTask?.now(); }, stop: (name: keyof TJobs) => { const job = jobRegistry.get(name as string); if (!job) return; options.logger.logInfo(`Stopping schedule cron job ${job.name}.`); - job.scheduledTask.stop(); + job.scheduledTask?.stop(); }, stopAll: () => { for (const job of jobRegistry.values()) { options.logger.logInfo(`Stopping schedule cron job ${job.name}.`); - job.scheduledTask.stop(); + job.scheduledTask?.stop(); } }, getJobRegistry() { diff --git a/packages/cron-jobs/package.json b/packages/cron-jobs/package.json index eefd24d79..12ed55a0d 100644 --- a/packages/cron-jobs/package.json +++ b/packages/cron-jobs/package.json @@ -24,10 +24,12 @@ "dependencies": { "@extractus/feed-extractor": "^7.1.3", "@homarr/analytics": "workspace:^0.1.0", + "@homarr/auth": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", "@homarr/cron-job-status": "workspace:^0.1.0", "@homarr/cron-jobs-core": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", + "@homarr/definitions": "workspace:^0.1.0", "@homarr/icons": "workspace:^0.1.0", "@homarr/integrations": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", @@ -41,7 +43,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-jobs/src/index.ts b/packages/cron-jobs/src/index.ts index 7e2d357e0..8a358988f 100644 --- a/packages/cron-jobs/src/index.ts +++ b/packages/cron-jobs/src/index.ts @@ -11,6 +11,7 @@ import { mediaServerJob } from "./jobs/integrations/media-server"; import { pingJob } from "./jobs/ping"; import type { RssFeed } from "./jobs/rss-feeds"; import { rssFeedsJob } from "./jobs/rss-feeds"; +import { sessionCleanupJob } from "./jobs/session-cleanup"; import { createCronJobGroup } from "./lib"; export const jobGroup = createCronJobGroup({ @@ -26,6 +27,7 @@ export const jobGroup = createCronJobGroup({ rssFeeds: rssFeedsJob, indexerManager: indexerManagerJob, healthMonitoring: healthMonitoringJob, + sessionCleanup: sessionCleanupJob, }); export type JobGroupKeys = ReturnType<(typeof jobGroup)["getKeys"]>[number]; diff --git a/packages/cron-jobs/src/jobs/integrations/media-organizer.ts b/packages/cron-jobs/src/jobs/integrations/media-organizer.ts index be088b448..ede54eaf7 100644 --- a/packages/cron-jobs/src/jobs/integrations/media-organizer.ts +++ b/packages/cron-jobs/src/jobs/integrations/media-organizer.ts @@ -1,7 +1,6 @@ import dayjs from "dayjs"; import SuperJSON from "superjson"; -import type { Modify } from "@homarr/common/types"; import { EVERY_MINUTE } from "@homarr/cron-jobs-core/expressions"; import { db } from "@homarr/db"; import { getItemsWithIntegrationsAsync } from "@homarr/db/queries"; @@ -26,9 +25,7 @@ export const mediaOrganizerJob = createCronJob("mediaOrganizer", EVERY_MINUTE).w const end = dayjs().add(Number(options.filterFutureMonths), "months").toDate(); //Asserting the integration kind until all of them get implemented - const integrationInstance = integrationCreatorFromSecrets( - integration as Modify, - ); + const integrationInstance = integrationCreatorFromSecrets(integration); const events = await integrationInstance.getCalendarEventsAsync(start, end); diff --git a/packages/cron-jobs/src/jobs/session-cleanup.ts b/packages/cron-jobs/src/jobs/session-cleanup.ts new file mode 100644 index 000000000..f9d382ad5 --- /dev/null +++ b/packages/cron-jobs/src/jobs/session-cleanup.ts @@ -0,0 +1,38 @@ +import { env } from "@homarr/auth/env.mjs"; +import { NEVER } from "@homarr/cron-jobs-core/expressions"; +import { db, eq, inArray } from "@homarr/db"; +import { sessions, users } from "@homarr/db/schema/sqlite"; +import { supportedAuthProviders } from "@homarr/definitions"; +import { logger } from "@homarr/log"; + +import { createCronJob } from "../lib"; + +/** + * Deletes sessions for users that have inactive auth providers. + * Sessions from other providers are deleted so they can no longer be used. + */ +export const sessionCleanupJob = createCronJob("sessionCleanup", NEVER, { + runOnStart: true, +}).withCallback(async () => { + const currentAuthProviders = env.AUTH_PROVIDERS; + + const inactiveAuthProviders = supportedAuthProviders.filter((provider) => !currentAuthProviders.includes(provider)); + const subQuery = db + .select({ id: users.id }) + .from(users) + .where(inArray(users.provider, inactiveAuthProviders)) + .as("sq"); + const sessionsWithInactiveProviders = await db + .select({ userId: sessions.userId }) + .from(sessions) + .rightJoin(subQuery, eq(sessions.userId, subQuery.id)); + + const userIds = sessionsWithInactiveProviders.map(({ userId }) => userId).filter((value) => value !== null); + await db.delete(sessions).where(inArray(sessions.userId, userIds)); + + if (sessionsWithInactiveProviders.length > 0) { + logger.info(`Deleted sessions for inactive providers count=${userIds.length}`); + } else { + logger.debug("No sessions to delete"); + } +}); diff --git a/packages/db/package.json b/packages/db/package.json index 915848939..7d38d3422 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -35,26 +35,26 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@auth/core": "^0.37.3", + "@auth/core": "^0.37.4", "@homarr/common": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", "@paralleldrive/cuid2": "^2.2.2", - "@testcontainers/mysql": "^10.14.0", + "@testcontainers/mysql": "^10.15.0", "better-sqlite3": "^11.5.0", "dotenv": "^16.4.5", "drizzle-kit": "^0.28.1", - "drizzle-orm": "^0.36.3", + "drizzle-orm": "^0.36.4", "mysql2": "3.11.4" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/better-sqlite3": "7.6.11", - "dotenv-cli": "^7.4.2", - "eslint": "^9.14.0", + "@types/better-sqlite3": "7.6.12", + "dotenv-cli": "^7.4.4", + "eslint": "^9.15.0", "prettier": "^3.3.3", "tsx": "4.19.2", "typescript": "^5.6.3" diff --git a/packages/definitions/package.json b/packages/definitions/package.json index 92f3c647a..533a74e75 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/definitions/src/permissions.ts b/packages/definitions/src/permissions.ts index 14ff21c46..0ceb648be 100644 --- a/packages/definitions/src/permissions.ts +++ b/packages/definitions/src/permissions.ts @@ -36,8 +36,13 @@ export type IntegrationPermission = (typeof integrationPermissions)[number]; * For example "board-create" is a generated key */ export const groupPermissions = { + // Order is the same in the UI, inspired from order in navigation here board: ["create", "view-all", "modify-all", "full-all"], + app: ["create", "use-all", "modify-all", "full-all"], integration: ["create", "use-all", "interact-all", "full-all"], + "search-engine": ["create", "modify-all", "full-all"], + media: ["upload", "view-all", "full-all"], + other: ["view-logs"], admin: true, } as const; @@ -49,9 +54,21 @@ export const groupPermissions = { const groupPermissionParents = { "board-modify-all": ["board-view-all"], "board-full-all": ["board-modify-all", "board-create"], + "app-modify-all": ["app-create"], + "app-full-all": ["app-modify-all", "app-use-all"], "integration-interact-all": ["integration-use-all"], "integration-full-all": ["integration-interact-all", "integration-create"], - admin: ["board-full-all", "integration-full-all"], + "search-engine-modify-all": ["search-engine-create"], + "search-engine-full-all": ["search-engine-modify-all"], + "media-full-all": ["media-upload", "media-view-all"], + admin: [ + "board-full-all", + "app-full-all", + "integration-full-all", + "search-engine-full-all", + "media-full-all", + "other-view-logs", + ], } satisfies Partial>; export const getPermissionsWithParents = (permissions: GroupPermissionKey[]): GroupPermissionKey[] => { diff --git a/packages/form/package.json b/packages/form/package.json index 329a19d46..1ee9292f2 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -24,13 +24,13 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/form": "^7.14.0" + "@mantine/form": "^7.14.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/icons/package.json b/packages/icons/package.json index 2e556df70..9e13bcf91 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -30,7 +30,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 6eea20ac9..0005c7e61 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -24,8 +24,8 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@ctrl/deluge": "^6.1.0", - "@ctrl/qbittorrent": "^9.0.1", + "@ctrl/deluge": "^7.0.0", + "@ctrl/qbittorrent": "^9.1.0", "@ctrl/transmission": "^7.1.0", "@homarr/common": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", @@ -41,7 +41,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/xml2js": "^0.4.14", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index 5894aea9e..4c6e2aa6d 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -12,7 +12,9 @@ import { TransmissionIntegration } from "../download-client/transmission/transmi import { HomeAssistantIntegration } from "../homeassistant/homeassistant-integration"; import { JellyfinIntegration } from "../jellyfin/jellyfin-integration"; import { JellyseerrIntegration } from "../jellyseerr/jellyseerr-integration"; +import { LidarrIntegration } from "../media-organizer/lidarr/lidarr-integration"; import { RadarrIntegration } from "../media-organizer/radarr/radarr-integration"; +import { ReadarrIntegration } from "../media-organizer/readarr/readarr-integration"; import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration"; import { OpenMediaVaultIntegration } from "../openmediavault/openmediavault-integration"; import { OverseerrIntegration } from "../overseerr/overseerr-integration"; @@ -64,4 +66,6 @@ export const integrationCreators = { overseerr: OverseerrIntegration, prowlarr: ProwlarrIntegration, openmediavault: OpenMediaVaultIntegration, -} satisfies Partial Integration>>; + lidarr: LidarrIntegration, + readarr: ReadarrIntegration, +} satisfies Record Integration>; diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index 8a0556c6b..ea13ce13b 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -16,6 +16,8 @@ export { OverseerrIntegration } from "./overseerr/overseerr-integration"; export { PiHoleIntegration } from "./pi-hole/pi-hole-integration"; export { PlexIntegration } from "./plex/plex-integration"; export { ProwlarrIntegration } from "./prowlarr/prowlarr-integration"; +export { LidarrIntegration } from "./media-organizer/lidarr/lidarr-integration"; +export { ReadarrIntegration } from "./media-organizer/readarr/readarr-integration"; // Types export type { IntegrationInput } from "./base/integration"; diff --git a/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts b/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts new file mode 100644 index 000000000..dcf6f5913 --- /dev/null +++ b/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts @@ -0,0 +1,127 @@ +import { logger } from "@homarr/log"; +import { z } from "@homarr/validation"; + +import type { CalendarEvent } from "../../calendar-types"; +import { MediaOrganizerIntegration } from "../media-organizer-integration"; + +export class LidarrIntegration extends MediaOrganizerIntegration { + public async testConnectionAsync(): Promise { + await super.handleTestConnectionResponseAsync({ + queryFunctionAsync: async () => { + return await fetch(`${this.integration.url}/api`, { + headers: { "X-Api-Key": super.getSecretValue("apiKey") }, + }); + }, + }); + } + + /** + * Gets the events in the Lidarr calendar between two dates. + * @param start The start date + * @param end The end date + * @param includeUnmonitored When true results will include unmonitored items of the Tadarr library. + */ + async getCalendarEventsAsync(start: Date, end: Date, includeUnmonitored = true): Promise { + const url = new URL(this.integration.url); + url.pathname = "/api/v1/calendar"; + url.searchParams.append("start", start.toISOString()); + url.searchParams.append("end", end.toISOString()); + url.searchParams.append("unmonitored", includeUnmonitored ? "true" : "false"); + const response = await fetch(url, { + headers: { + "X-Api-Key": super.getSecretValue("apiKey"), + }, + }); + const lidarrCalendarEvents = await z.array(lidarrCalendarEventSchema).parseAsync(await response.json()); + + return lidarrCalendarEvents.map((lidarrCalendarEvent): CalendarEvent => { + return { + name: lidarrCalendarEvent.title, + subName: lidarrCalendarEvent.artist.artistName, + description: lidarrCalendarEvent.overview, + thumbnail: this.chooseBestImageAsURL(lidarrCalendarEvent), + date: lidarrCalendarEvent.releaseDate, + mediaInformation: { + type: "audio", + }, + links: this.getLinksForLidarrCalendarEvent(lidarrCalendarEvent), + }; + }); + } + + private getLinksForLidarrCalendarEvent = (event: z.infer) => { + const links: CalendarEvent["links"] = []; + + for (const link of event.artist.links) { + switch (link.name) { + case "vgmdb": + links.push({ + href: link.url, + name: "VgmDB", + color: "#f5c518", + isDark: false, + logo: "/images/apps/vgmdb.svg", + notificationColor: "cyan", + }); + break; + case "imdb": + links.push({ + href: link.url, + name: "IMDb", + color: "#f5c518", + isDark: false, + logo: "/images/apps/imdb.png", + notificationColor: "cyan", + }); + break; + case "last": + links.push({ + href: link.url, + name: "LastFM", + color: "#cf222a", + isDark: false, + logo: "/images/apps/lastfm.svg", + notificationColor: "cyan", + }); + break; + } + } + + return links; + }; + + private chooseBestImage = ( + event: z.infer, + ): z.infer["images"][number] | undefined => { + const flatImages = [...event.images]; + + const sortedImages = flatImages.sort( + (imageA, imageB) => this.priorities.indexOf(imageA.coverType) - this.priorities.indexOf(imageB.coverType), + ); + logger.debug(`Sorted images to [${sortedImages.map((image) => image.coverType).join(",")}]`); + return sortedImages[0]; + }; + + private chooseBestImageAsURL = (event: z.infer): string | undefined => { + const bestImage = this.chooseBestImage(event); + if (!bestImage) { + return undefined; + } + return bestImage.remoteUrl; + }; +} + +const lidarrCalendarEventImageSchema = z.array( + z.object({ + coverType: z.enum(["screenshot", "poster", "banner", "fanart", "clearlogo", "cover"]), + remoteUrl: z.string().url(), + }), +); + +const lidarrCalendarEventSchema = z.object({ + title: z.string(), + overview: z.string().optional(), + images: lidarrCalendarEventImageSchema, + artist: z.object({ links: z.array(z.object({ url: z.string().url(), name: z.string() })), artistName: z.string() }), + releaseDate: z.string().transform((value) => new Date(value)), +}); diff --git a/packages/integrations/src/media-organizer/media-organizer-integration.ts b/packages/integrations/src/media-organizer/media-organizer-integration.ts new file mode 100644 index 000000000..3b841e7c0 --- /dev/null +++ b/packages/integrations/src/media-organizer/media-organizer-integration.ts @@ -0,0 +1,17 @@ +import { Integration } from "../base/integration"; + +export abstract class MediaOrganizerIntegration extends Integration { + /** + * Priority list that determines the quality of images using their order. + * Types at the start of the list are better than those at the end. + * We do this to attempt to find the best quality image for the show. + */ + protected readonly priorities: string[] = [ + "cover", // Official, perfect aspect ratio + "poster", // Official, perfect aspect ratio + "banner", // Official, bad aspect ratio + "fanart", // Unofficial, possibly bad quality + "screenshot", // Bad aspect ratio, possibly bad quality + "clearlogo", // Without background, bad aspect ratio + ]; +} diff --git a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts index a562ce2d0..e1387408c 100644 --- a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts +++ b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts @@ -2,24 +2,11 @@ import type { AtLeastOneOf } from "@homarr/common/types"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; -import { Integration } from "../../base/integration"; import type { CalendarEvent } from "../../calendar-types"; import { radarrReleaseTypes } from "../../calendar-types"; +import { MediaOrganizerIntegration } from "../media-organizer-integration"; -export class RadarrIntegration extends Integration { - /** - * Priority list that determines the quality of images using their order. - * Types at the start of the list are better than those at the end. - * We do this to attempt to find the best quality image for the show. - */ - private readonly priorities: z.infer["images"][number]["coverType"][] = [ - "poster", // Official, perfect aspect ratio - "banner", // Official, bad aspect ratio - "fanart", // Unofficial, possibly bad quality - "screenshot", // Bad aspect ratio, possibly bad quality - "clearlogo", // Without background, bad aspect ratio - ]; - +export class RadarrIntegration extends MediaOrganizerIntegration { /** * Gets the events in the Radarr calendar between two dates. * @param start The start date @@ -76,7 +63,7 @@ export class RadarrIntegration extends Integration { name: "IMDb", color: "#f5c518", isDark: false, - logo: "/images/apps/imdb.png", + logo: "/images/apps/imdb.svg", }); } diff --git a/packages/integrations/src/media-organizer/readarr/readarr-integration.ts b/packages/integrations/src/media-organizer/readarr/readarr-integration.ts new file mode 100644 index 000000000..4283c39fa --- /dev/null +++ b/packages/integrations/src/media-organizer/readarr/readarr-integration.ts @@ -0,0 +1,114 @@ +import { logger } from "@homarr/log"; +import { z } from "@homarr/validation"; + +import type { CalendarEvent } from "../../calendar-types"; +import { MediaOrganizerIntegration } from "../media-organizer-integration"; + +export class ReadarrIntegration extends MediaOrganizerIntegration { + public async testConnectionAsync(): Promise { + await super.handleTestConnectionResponseAsync({ + queryFunctionAsync: async () => { + return await fetch(`${this.integration.url}/api`, { + headers: { "X-Api-Key": super.getSecretValue("apiKey") }, + }); + }, + }); + } + + /** + * Gets the events in the Lidarr calendar between two dates. + * @param start The start date + * @param end The end date + * @param includeUnmonitored When true results will include unmonitored items of the Tadarr library. + */ + async getCalendarEventsAsync( + start: Date, + end: Date, + includeUnmonitored = true, + includeAuthor = true, + ): Promise { + const url = new URL(this.integration.url); + url.pathname = "/api/v1/calendar"; + url.searchParams.append("start", start.toISOString()); + url.searchParams.append("end", end.toISOString()); + url.searchParams.append("unmonitored", includeUnmonitored.toString()); + url.searchParams.append("includeAuthor", includeAuthor.toString()); + const response = await fetch(url, { + headers: { + "X-Api-Key": super.getSecretValue("apiKey"), + }, + }); + const readarrCalendarEvents = await z.array(readarrCalendarEventSchema).parseAsync(await response.json()); + + return readarrCalendarEvents.map((readarrCalendarEvent): CalendarEvent => { + return { + name: readarrCalendarEvent.title, + subName: readarrCalendarEvent.author.authorName, + description: readarrCalendarEvent.overview, + thumbnail: this.chooseBestImageAsURL(readarrCalendarEvent), + date: readarrCalendarEvent.releaseDate, + mediaInformation: { + type: "audio", + }, + links: this.getLinksForReadarrCalendarEvent(readarrCalendarEvent), + }; + }); + } + + private getLinksForReadarrCalendarEvent = (event: z.infer) => { + return [ + { + href: `${this.integration.url}/author/${event.author.foreignAuthorId}`, + color: "#f5c518", + isDark: false, + logo: "/images/apps/readarr.svg", + name: "Readarr", + notificationColor: "#f5c518", + }, + ] satisfies CalendarEvent["links"]; + }; + + private chooseBestImage = ( + event: z.infer, + ): z.infer["images"][number] | undefined => { + const flatImages = [...event.images]; + + const sortedImages = flatImages.sort( + (imageA, imageB) => this.priorities.indexOf(imageA.coverType) - this.priorities.indexOf(imageB.coverType), + ); + logger.debug(`Sorted images to [${sortedImages.map((image) => image.coverType).join(",")}]`); + return sortedImages[0]; + }; + + private chooseBestImageAsURL = (event: z.infer): string | undefined => { + const bestImage = this.chooseBestImage(event); + if (!bestImage) { + return undefined; + } + return `${this.integration.url}${bestImage.url}`; + }; +} + +const readarrCalendarEventImageSchema = z.array( + z.object({ + coverType: z.enum(["screenshot", "poster", "banner", "fanart", "clearlogo", "cover"]), + url: z.string().transform((url) => url.replace(/\?lastWrite=[0-9]+/, "")), // returns a random string, needs to be removed for loading the image + }), +); + +const readarrCalendarEventSchema = z.object({ + title: z.string(), + overview: z.string().optional(), + images: readarrCalendarEventImageSchema, + links: z.array( + z.object({ + name: z.string(), + url: z.string(), + }), + ), + author: z.object({ + authorName: z.string(), + foreignAuthorId: z.string(), + }), + releaseDate: z.string().transform((value) => new Date(value)), +}); diff --git a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts index 0b18e2b0a..aeb54fe4d 100644 --- a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts +++ b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts @@ -1,23 +1,10 @@ import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; -import { Integration } from "../../base/integration"; import type { CalendarEvent } from "../../calendar-types"; +import { MediaOrganizerIntegration } from "../media-organizer-integration"; -export class SonarrIntegration extends Integration { - /** - * Priority list that determines the quality of images using their order. - * Types at the start of the list are better than those at the end. - * We do this to attempt to find the best quality image for the show. - */ - private readonly priorities: z.infer["images"][number]["coverType"][] = [ - "poster", // Official, perfect aspect ratio - "banner", // Official, bad aspect ratio - "fanart", // Unofficial, possibly bad quality - "screenshot", // Bad aspect ratio, possibly bad quality - "clearlogo", // Without background, bad aspect ratio - ]; - +export class SonarrIntegration extends MediaOrganizerIntegration { /** * Gets the events in the Sonarr calendar between two dates. * @param start The start date @@ -75,7 +62,7 @@ export class SonarrIntegration extends Integration { name: "IMDb", color: "#f5c518", isDark: false, - logo: "/images/apps/imdb.png", + logo: "/images/apps/imdb.svg", }); } diff --git a/packages/log/package.json b/packages/log/package.json index 48a6d7b67..048bc0dad 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -34,7 +34,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/modals-collection/package.json b/packages/modals-collection/package.json index 1d9cdd25b..7de3da9f6 100644 --- a/packages/modals-collection/package.json +++ b/packages/modals-collection/package.json @@ -30,7 +30,7 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.14.0", + "@mantine/core": "^7.14.1", "@tabler/icons-react": "^3.22.0", "dayjs": "^1.11.13", "next": "^14.2.18", @@ -40,7 +40,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/modals/package.json b/packages/modals/package.json index 34f48f4f4..8f2ef022e 100644 --- a/packages/modals/package.json +++ b/packages/modals/package.json @@ -24,15 +24,15 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.14.0", - "@mantine/hooks": "^7.14.0", + "@mantine/core": "^7.14.1", + "@mantine/hooks": "^7.14.1", "react": "^18.3.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 4db4520af..f2ddb2e9b 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -24,14 +24,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/ui": "workspace:^0.1.0", - "@mantine/notifications": "^7.14.0", + "@mantine/notifications": "^7.14.1", "@tabler/icons-react": "^3.22.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/old-import/package.json b/packages/old-import/package.json index f583585d5..08864fada 100644 --- a/packages/old-import/package.json +++ b/packages/old-import/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/old-schema/package.json b/packages/old-schema/package.json index fe72d60a2..16723dd3d 100644 --- a/packages/old-schema/package.json +++ b/packages/old-schema/package.json @@ -27,7 +27,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/old-schema/src/app.ts b/packages/old-schema/src/app.ts index 0befa9ae2..5a4fb5421 100644 --- a/packages/old-schema/src/app.ts +++ b/packages/old-schema/src/app.ts @@ -4,27 +4,24 @@ import { tileBaseSchema } from "./tile"; const appBehaviourSchema = z.object({ externalUrl: z.string(), - isOpeningNewTab: z.boolean(), - tooltipDescription: z.string().optional(), + isOpeningNewTab: z.boolean().catch(true), + tooltipDescription: z.string().optional().catch(undefined), }); const appNetworkSchema = z.object({ - enabledStatusChecker: z.boolean(), - okStatus: z.array(z.number()).optional(), - statusCodes: z.array(z.string()), + enabledStatusChecker: z.boolean().catch(true), + okStatus: z.array(z.number()).optional().catch([]), + statusCodes: z.array(z.string()).catch([]), }); const appAppearanceSchema = z.object({ iconUrl: z.string(), - appNameStatus: z.union([z.literal("normal"), z.literal("hover"), z.literal("hidden")]), - positionAppName: z.union([ - z.literal("row"), - z.literal("column"), - z.literal("row-reverse"), - z.literal("column-reverse"), - ]), - appNameFontSize: z.number(), - lineClampAppName: z.number(), + appNameStatus: z.union([z.literal("normal"), z.literal("hover"), z.literal("hidden")]).catch("normal"), + positionAppName: z + .union([z.literal("row"), z.literal("column"), z.literal("row-reverse"), z.literal("column-reverse")]) + .catch("column"), + appNameFontSize: z.number().catch(16), + lineClampAppName: z.number().catch(1), }); const integrationSchema = z.enum([ diff --git a/packages/ping/package.json b/packages/ping/package.json index 0556df082..1f95751a3 100644 --- a/packages/ping/package.json +++ b/packages/ping/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/redis/package.json b/packages/redis/package.json index b628dd3c8..c46058977 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/server-settings/package.json b/packages/server-settings/package.json index f2cb2d514..e9e0ab806 100644 --- a/packages/server-settings/package.json +++ b/packages/server-settings/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/spotlight/package.json b/packages/spotlight/package.json index 71bf46668..b9dc3b208 100644 --- a/packages/spotlight/package.json +++ b/packages/spotlight/package.json @@ -31,11 +31,11 @@ "@homarr/modals-collection": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.14.0", - "@mantine/hooks": "^7.14.0", - "@mantine/spotlight": "^7.14.0", + "@mantine/core": "^7.14.1", + "@mantine/hooks": "^7.14.1", + "@mantine/spotlight": "^7.14.1", "@tabler/icons-react": "^3.22.0", - "jotai": "^2.10.2", + "jotai": "^2.10.3", "next": "^14.2.18", "react": "^18.3.1", "use-deep-compare-effect": "^1.8.1" @@ -44,7 +44,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx index 2de76db8c..02251fe32 100644 --- a/packages/spotlight/src/components/spotlight.tsx +++ b/packages/spotlight/src/components/spotlight.tsx @@ -1,5 +1,6 @@ "use client"; +import type { Dispatch, SetStateAction } from "react"; import { useMemo, useRef, useState } from "react"; import { ActionIcon, Center, Group, Kbd } from "@mantine/core"; import { Spotlight as MantineSpotlight } from "@mantine/spotlight"; @@ -9,23 +10,42 @@ import type { TranslationObject } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; import type { inferSearchInteractionOptions } from "../lib/interaction"; +import type { SearchMode } from "../lib/mode"; import { searchModes } from "../modes"; import { selectAction, spotlightStore } from "../spotlight-store"; import { SpotlightChildrenActions } from "./actions/children-actions"; import { SpotlightActionGroups } from "./actions/groups/action-group"; +type SearchModeKey = keyof TranslationObject["search"]["mode"]; + export const Spotlight = () => { - const [query, setQuery] = useState(""); - const [mode, setMode] = useState("help"); - const [childrenOptions, setChildrenOptions] = useState | null>(null); - const t = useI18n(); - const inputRef = useRef(null); + const searchModeState = useState("help"); + const mode = searchModeState[0]; const activeMode = useMemo(() => searchModes.find((searchMode) => searchMode.modeKey === mode), [mode]); if (!activeMode) { return null; } + // We use the "key" below to prevent the 'Different amounts of hooks' error + return ; +}; + +interface SpotlightWithActiveModeProps { + modeState: [SearchModeKey, Dispatch>]; + activeMode: SearchMode; +} + +const SpotlightWithActiveMode = ({ modeState, activeMode }: SpotlightWithActiveModeProps) => { + const [query, setQuery] = useState(""); + const [mode, setMode] = modeState; + const [childrenOptions, setChildrenOptions] = useState | null>(null); + const t = useI18n(); + const inputRef = useRef(null); + // Works as always the same amount of hooks are executed + const useGroups = "groups" in activeMode ? () => activeMode.groups : activeMode.useGroups; + const groups = useGroups(); + return ( { }); }} query={query} - groups={activeMode.groups} + groups={groups} /> )} diff --git a/packages/spotlight/src/lib/mode.ts b/packages/spotlight/src/lib/mode.ts index a0b480f3c..358432107 100644 --- a/packages/spotlight/src/lib/mode.ts +++ b/packages/spotlight/src/lib/mode.ts @@ -2,8 +2,14 @@ import type { TranslationObject } from "@homarr/translation"; import type { SearchGroup } from "./group"; -export interface SearchMode { +export type SearchMode = { modeKey: keyof TranslationObject["search"]["mode"]; character: string; - groups: SearchGroup[]; -} +} & ( + | { + groups: SearchGroup[]; + } + | { + useGroups: () => SearchGroup[]; + } +); diff --git a/packages/spotlight/src/modes/app-integration-board/index.tsx b/packages/spotlight/src/modes/app-integration-board/index.tsx index 417fe967c..4fe5de9fd 100644 --- a/packages/spotlight/src/modes/app-integration-board/index.tsx +++ b/packages/spotlight/src/modes/app-integration-board/index.tsx @@ -1,3 +1,6 @@ +import { useSession } from "@homarr/auth/client"; + +import type { SearchGroup } from "../../lib/group"; import type { SearchMode } from "../../lib/mode"; import { appsSearchGroup } from "./apps-search-group"; import { boardsSearchGroup } from "./boards-search-group"; @@ -6,5 +9,14 @@ import { integrationsSearchGroup } from "./integrations-search-group"; export const appIntegrationBoardMode = { modeKey: "appIntegrationBoard", character: "#", - groups: [appsSearchGroup, integrationsSearchGroup, boardsSearchGroup], + useGroups() { + const { data: session } = useSession(); + const groups: SearchGroup[] = [boardsSearchGroup]; + + if (!session?.user) { + return groups; + } + + return groups.concat([appsSearchGroup, integrationsSearchGroup]); + }, } satisfies SearchMode; diff --git a/packages/spotlight/src/modes/command/index.tsx b/packages/spotlight/src/modes/command/index.tsx index 6d57a9a90..4290c7c1e 100644 --- a/packages/spotlight/src/modes/command/index.tsx +++ b/packages/spotlight/src/modes/command/index.tsx @@ -1,11 +1,11 @@ import { Group, Text, useMantineColorScheme } from "@mantine/core"; import { + IconBox, IconCategoryPlus, IconFileImport, IconLanguage, IconMailForward, IconMoon, - IconPackage, IconPlug, IconSun, IconUserPlus, @@ -113,9 +113,10 @@ export const commandMode = { }, { commandKey: "newApp", - icon: IconPackage, + icon: IconBox, name: tOption("newApp.label"), useInteraction: interaction.link(() => ({ href: "/manage/apps/new" })), + hidden: !session?.user.permissions.includes("app-create"), }, { commandKey: "newIntegration", diff --git a/packages/spotlight/src/modes/index.tsx b/packages/spotlight/src/modes/index.tsx index eb286a1cd..f95b1145e 100644 --- a/packages/spotlight/src/modes/index.tsx +++ b/packages/spotlight/src/modes/index.tsx @@ -1,6 +1,7 @@ import { Group, Kbd, Text } from "@mantine/core"; import { IconBook2, IconBrandDiscord, IconBrandGithub } from "@tabler/icons-react"; +import { useSession } from "@homarr/auth/client"; import { createDocumentationLink } from "@homarr/definitions"; import { useScopedI18n } from "@homarr/translation/client"; @@ -18,58 +19,67 @@ const searchModesWithoutHelp = [userGroupMode, appIntegrationBoardMode, external const helpMode = { modeKey: "help", character: "?", - groups: [ - createGroup({ - keyPath: "character", - title: (t) => t("search.mode.help.group.mode.title"), - options: searchModesWithoutHelp.map(({ character, modeKey }) => ({ character, modeKey })), - Component: ({ modeKey, character }) => { - const t = useScopedI18n(`search.mode.${modeKey}`); + useGroups() { + const { data: session } = useSession(); + const visibleSearchModes: SearchMode[] = [appIntegrationBoardMode, externalMode, commandMode, pageMode]; - return ( - - {t("help")} - {character} + if (session?.user.permissions.includes("admin")) { + visibleSearchModes.unshift(userGroupMode); + } + + return [ + createGroup({ + keyPath: "character", + title: (t) => t("search.mode.help.group.mode.title"), + options: visibleSearchModes.map(({ character, modeKey }) => ({ character, modeKey })), + Component: ({ modeKey, character }) => { + const t = useScopedI18n(`search.mode.${modeKey}`); + + return ( + + {t("help")} + {character} + + ); + }, + filter: () => true, + useInteraction: interaction.mode(({ modeKey }) => ({ mode: modeKey })), + }), + createGroup({ + keyPath: "href", + title: (t) => t("search.mode.help.group.help.title"), + useOptions() { + const t = useScopedI18n("search.mode.help.group.help.option"); + + return [ + { + label: t("documentation.label"), + icon: IconBook2, + href: createDocumentationLink("/docs/getting-started"), + }, + { + label: t("submitIssue.label"), + icon: IconBrandGithub, + href: "https://github.com/ajnart/homarr/issues/new/choose", + }, + { + label: t("discord.label"), + icon: IconBrandDiscord, + href: "https://discord.com/invite/aCsmEV5RgA", + }, + ]; + }, + Component: (props) => ( + + + {props.label} - ); - }, - filter: () => true, - useInteraction: interaction.mode(({ modeKey }) => ({ mode: modeKey })), - }), - createGroup({ - keyPath: "href", - title: (t) => t("search.mode.help.group.help.title"), - useOptions() { - const t = useScopedI18n("search.mode.help.group.help.option"); - - return [ - { - label: t("documentation.label"), - icon: IconBook2, - href: createDocumentationLink("/docs/getting-started"), - }, - { - label: t("submitIssue.label"), - icon: IconBrandGithub, - href: "https://github.com/ajnart/homarr/issues/new/choose", - }, - { - label: t("discord.label"), - icon: IconBrandDiscord, - href: "https://discord.com/invite/aCsmEV5RgA", - }, - ]; - }, - Component: (props) => ( - - - {props.label} - - ), - filter: () => true, - useInteraction: interaction.link(({ href }) => ({ href, newTab: true })), - }), - ], + ), + filter: () => true, + useInteraction: interaction.link(({ href }) => ({ href, newTab: true })), + }), + ]; + }, } satisfies SearchMode; export const searchModes = [...searchModesWithoutHelp, helpMode] as const; diff --git a/packages/spotlight/src/modes/page/pages-search-group.tsx b/packages/spotlight/src/modes/page/pages-search-group.tsx index 9383631ef..d9b419340 100644 --- a/packages/spotlight/src/modes/page/pages-search-group.tsx +++ b/packages/spotlight/src/modes/page/pages-search-group.tsx @@ -130,7 +130,7 @@ export const pagesSearchGroup = createGroup<{ icon: IconLogs, path: "/manage/tools/logs", name: t("manageLog.label"), - hidden: !session?.user.permissions.includes("admin"), + hidden: !session?.user.permissions.includes("other-view-logs"), }, { icon: IconReport, diff --git a/packages/translation/package.json b/packages/translation/package.json index 4694624c4..27c2338db 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -40,7 +40,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 849a8f662..7910e01ea 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -196,6 +196,27 @@ } } }, + "app": { + "title": "Apps", + "item": { + "create": { + "label": "Create apps", + "description": "Allow members to create apps" + }, + "use-all": { + "label": "Use all apps", + "description": "Allow members to add any apps to their boards" + }, + "modify-all": { + "label": "Modify all apps", + "description": "Allow members to modify all apps" + }, + "full-all": { + "label": "Full app access", + "description": "Allow members to manage, use and delete any app" + } + } + }, "board": { "title": "Boards", "item": { @@ -237,6 +258,49 @@ "description": "Allow members to manage, use and interact with any integration" } } + }, + "media": { + "title": "Medias", + "item": { + "upload": { + "label": "Upload medias", + "description": "Allow members to upload medias" + }, + "view-all": { + "label": "View all medias", + "description": "Allow members to view all medias" + }, + "full-all": { + "label": "Full media access", + "description": "Allow members to manage and delete any media" + } + } + }, + "other": { + "title": "Other", + "item": { + "view-logs": { + "label": "View logs", + "description": "Allow members to view logs" + } + } + }, + "search-engine": { + "title": "Search engines", + "item": { + "create": { + "label": "Create search engines", + "description": "Allow members to create search engines" + }, + "modify-all": { + "label": "Modify all search engines", + "description": "Allow members to modify all search engines" + }, + "full-all": { + "label": "Full search engine access", + "description": "Allow members to manage and delete any search engine" + } + } } }, "memberNotice": { @@ -244,7 +308,7 @@ "external": "All members are from external providers and cannot be managed here" }, "reservedNotice": { - "message": "This group is reserved for system use and restricts some actions. {checkoutDocs}" + "message": "This group is reserved for system use and restricts some actions. " }, "action": { "create": { @@ -2073,6 +2137,9 @@ }, "dnsHole": { "label": "DNS Hole Data" + }, + "sessionCleanup": { + "label": "Session Cleanup" } } }, diff --git a/packages/ui/package.json b/packages/ui/package.json index b5a7d6754..01820d918 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -28,9 +28,9 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.14.0", - "@mantine/dates": "^7.14.0", - "@mantine/hooks": "^7.14.0", + "@mantine/core": "^7.14.1", + "@mantine/dates": "^7.14.1", + "@mantine/hooks": "^7.14.1", "@tabler/icons-react": "^3.22.0", "mantine-react-table": "2.0.0-beta.7", "next": "^14.2.18", @@ -41,7 +41,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/css-modules": "^1.0.5", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/validation/package.json b/packages/validation/package.json index 951af609a..03f5b2b96 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/packages/validation/src/icons.ts b/packages/validation/src/icons.ts index 031878b99..c621ecea5 100644 --- a/packages/validation/src/icons.ts +++ b/packages/validation/src/icons.ts @@ -2,6 +2,7 @@ import { z } from "zod"; const findIconsSchema = z.object({ searchText: z.string().optional(), + limitPerGroup: z.number().min(1).max(500).default(12), }); export const iconsSchemas = { diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 16f97c80c..663a03780 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -40,24 +40,24 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.14.0", - "@mantine/hooks": "^7.14.0", + "@mantine/core": "^7.14.1", + "@mantine/hooks": "^7.14.1", "@tabler/icons-react": "^3.22.0", - "@tiptap/extension-color": "2.9.1", - "@tiptap/extension-highlight": "2.9.1", - "@tiptap/extension-image": "2.9.1", - "@tiptap/extension-link": "^2.9.1", - "@tiptap/extension-table": "2.9.1", - "@tiptap/extension-table-cell": "2.9.1", - "@tiptap/extension-table-header": "2.9.1", - "@tiptap/extension-table-row": "2.9.1", - "@tiptap/extension-task-item": "2.9.1", - "@tiptap/extension-task-list": "2.9.1", - "@tiptap/extension-text-align": "2.9.1", - "@tiptap/extension-text-style": "2.9.1", - "@tiptap/extension-underline": "2.9.1", - "@tiptap/react": "^2.9.1", - "@tiptap/starter-kit": "^2.9.1", + "@tiptap/extension-color": "2.10.2", + "@tiptap/extension-highlight": "2.10.2", + "@tiptap/extension-image": "2.10.2", + "@tiptap/extension-link": "^2.10.2", + "@tiptap/extension-table": "2.10.2", + "@tiptap/extension-table-cell": "2.10.2", + "@tiptap/extension-table-header": "2.10.2", + "@tiptap/extension-table-row": "2.10.2", + "@tiptap/extension-task-item": "2.10.2", + "@tiptap/extension-task-list": "2.10.2", + "@tiptap/extension-text-align": "2.10.2", + "@tiptap/extension-text-style": "2.10.2", + "@tiptap/extension-underline": "2.10.2", + "@tiptap/react": "^2.10.2", + "@tiptap/starter-kit": "^2.10.2", "clsx": "^2.1.1", "dayjs": "^1.11.13", "mantine-react-table": "2.0.0-beta.7", @@ -70,7 +70,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/video.js": "^7.3.58", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 588e26cc8..f2916ee0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,11 +17,11 @@ importers: specifier: workspace:^0.1.0 version: link:tooling/prettier '@turbo/gen': - specifier: ^2.3.0 - version: 2.3.0(@types/node@22.9.0)(typescript@5.6.3) + specifier: ^2.3.1 + version: 2.3.1(@types/node@22.9.1)(typescript@5.6.3) '@vitejs/plugin-react': specifier: ^4.3.3 - version: 4.3.3(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + version: 4.3.3(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) '@vitest/coverage-v8': specifier: ^2.1.5 version: 2.1.5(vitest@2.1.5) @@ -38,20 +38,20 @@ importers: specifier: ^3.3.3 version: 3.3.3 testcontainers: - specifier: ^10.14.0 - version: 10.14.0 + specifier: ^10.15.0 + version: 10.15.0 turbo: - specifier: ^2.3.0 - version: 2.3.0 + specifier: ^2.3.1 + version: 2.3.1 typescript: specifier: ^5.6.3 version: 5.6.3 vite-tsconfig-paths: - specifier: ^5.1.2 - version: 5.1.2(typescript@5.6.3)(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + specifier: ^5.1.3 + version: 5.1.3(typescript@5.6.3)(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) vitest: specifier: ^2.1.5 - version: 2.1.5(@types/node@22.9.0)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + version: 2.1.5(@types/node@22.9.1)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) apps/nextjs: dependencies: @@ -122,20 +122,20 @@ importers: specifier: workspace:^0.1.0 version: link:../../packages/widgets '@mantine/colors-generator': - specifier: ^7.14.0 - version: 7.14.0(chroma-js@3.1.2) + specifier: ^7.14.1 + version: 7.14.1(chroma-js@3.1.2) '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) '@mantine/modals': - specifier: ^7.14.0 - version: 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/tiptap': - specifier: ^7.14.0 - version: 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tiptap/extension-link@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1))(@tiptap/react@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tiptap/extension-link@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2))(@tiptap/react@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@million/lint': specifier: 1.0.12 version: 1.0.12(rollup@4.21.3)(webpack-sources@3.2.3) @@ -146,23 +146,23 @@ importers: specifier: ^3.22.0 version: 3.22.0(react@18.3.1) '@tanstack/react-query': - specifier: ^5.60.5 - version: 5.60.5(react@18.3.1) + specifier: ^5.61.0 + version: 5.61.0(react@18.3.1) '@tanstack/react-query-devtools': - specifier: ^5.60.5 - version: 5.60.5(@tanstack/react-query@5.60.5(react@18.3.1))(react@18.3.1) + specifier: ^5.61.0 + version: 5.61.0(@tanstack/react-query@5.61.0(react@18.3.1))(react@18.3.1) '@tanstack/react-query-next-experimental': - specifier: 5.60.5 - version: 5.60.5(@tanstack/react-query@5.60.5(react@18.3.1))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react@18.3.1) + specifier: 5.61.0 + version: 5.61.0(@tanstack/react-query@5.61.0(react@18.3.1))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react@18.3.1) '@trpc/client': specifier: next version: 11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)) '@trpc/next': specifier: next - version: 11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@trpc/react-query': specifier: next - version: 11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@trpc/server': specifier: next version: 11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -194,11 +194,11 @@ importers: specifier: ^11.0.0 version: 11.0.0 jotai: - specifier: ^2.10.2 - version: 2.10.2(@types/react@18.3.12)(react@18.3.1) + specifier: ^2.10.3 + version: 2.10.3(@types/react@18.3.12)(react@18.3.1) mantine-react-table: specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.0.0-beta.7(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: specifier: ^14.2.18 version: 14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -246,8 +246,8 @@ importers: specifier: 2.4.4 version: 2.4.4 '@types/node': - specifier: ^22.9.0 - version: 22.9.0 + specifier: ^22.9.1 + version: 22.9.1 '@types/prismjs': specifier: ^1.26.5 version: 1.26.5 @@ -264,8 +264,8 @@ importers: specifier: ^9.1.0 version: 9.1.0 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 node-loader: specifier: ^2.1.0 version: 2.1.0(webpack@5.94.0) @@ -346,14 +346,14 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/node': - specifier: ^22.9.0 - version: 22.9.0 + specifier: ^22.9.1 + version: 22.9.1 dotenv-cli: - specifier: ^7.4.2 - version: 7.4.2 + specifier: ^7.4.4 + version: 7.4.4 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -413,8 +413,8 @@ importers: specifier: ^8.5.13 version: 8.5.13 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -450,8 +450,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -508,7 +508,7 @@ importers: version: 11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)) '@trpc/react-query': specifier: next - version: 11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@trpc/server': specifier: next version: 11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -538,11 +538,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/dockerode': - specifier: ^3.3.31 - version: 3.3.31 + specifier: ^3.3.32 + version: 3.3.32 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -553,11 +553,11 @@ importers: packages/auth: dependencies: '@auth/core': - specifier: ^0.37.3 - version: 0.37.3 + specifier: ^0.37.4 + version: 0.37.4 '@auth/drizzle-adapter': - specifier: ^1.7.3 - version: 1.7.3 + specifier: ^1.7.4 + version: 1.7.4 '@homarr/common': specifier: workspace:^0.1.0 version: link:../common @@ -614,8 +614,8 @@ importers: specifier: 0.9.0 version: 0.9.0 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -651,8 +651,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -672,8 +672,8 @@ importers: specifier: ^18.3.1 version: 18.3.1 tldts: - specifier: ^6.1.61 - version: 6.1.61 + specifier: ^6.1.63 + version: 6.1.63 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -685,8 +685,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -713,8 +713,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -735,8 +735,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -749,6 +749,9 @@ importers: '@homarr/analytics': specifier: workspace:^0.1.0 version: link:../analytics + '@homarr/auth': + specifier: workspace:^0.1.0 + version: link:../auth '@homarr/common': specifier: workspace:^0.1.0 version: link:../common @@ -761,6 +764,9 @@ importers: '@homarr/db': specifier: workspace:^0.1.0 version: link:../db + '@homarr/definitions': + specifier: workspace:^0.1.0 + version: link:../definitions '@homarr/icons': specifier: workspace:^0.1.0 version: link:../icons @@ -796,8 +802,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -824,8 +830,8 @@ importers: specifier: ^3.0.11 version: 3.0.11 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -833,8 +839,8 @@ importers: packages/db: dependencies: '@auth/core': - specifier: ^0.37.3 - version: 0.37.3 + specifier: ^0.37.4 + version: 0.37.4 '@homarr/common': specifier: workspace:^0.1.0 version: link:../common @@ -851,8 +857,8 @@ importers: specifier: ^2.2.2 version: 2.2.2 '@testcontainers/mysql': - specifier: ^10.14.0 - version: 10.14.0 + specifier: ^10.15.0 + version: 10.15.0 better-sqlite3: specifier: ^11.5.0 version: 11.5.0 @@ -863,8 +869,8 @@ importers: specifier: ^0.28.1 version: 0.28.1 drizzle-orm: - specifier: ^0.36.3 - version: 0.36.3(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.11)(@types/react@18.3.12)(better-sqlite3@11.5.0)(mysql2@3.11.4)(react@18.3.1) + specifier: ^0.36.4 + version: 0.36.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@18.3.12)(better-sqlite3@11.5.0)(mysql2@3.11.4)(react@18.3.1) mysql2: specifier: 3.11.4 version: 3.11.4 @@ -879,14 +885,14 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/better-sqlite3': - specifier: 7.6.11 - version: 7.6.11 + specifier: 7.6.12 + version: 7.6.12 dotenv-cli: - specifier: ^7.4.2 - version: 7.4.2 + specifier: ^7.4.4 + version: 7.4.4 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -913,8 +919,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -928,8 +934,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/form': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -941,8 +947,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -969,8 +975,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -978,11 +984,11 @@ importers: packages/integrations: dependencies: '@ctrl/deluge': - specifier: ^6.1.0 - version: 6.1.0 + specifier: ^7.0.0 + version: 7.0.0 '@ctrl/qbittorrent': - specifier: ^9.0.1 - version: 9.0.1 + specifier: ^9.1.0 + version: 9.1.0 '@ctrl/transmission': specifier: ^7.1.0 version: 7.1.0 @@ -1024,8 +1030,8 @@ importers: specifier: ^0.4.14 version: 0.4.14 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1052,8 +1058,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1067,11 +1073,11 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) react: specifier: ^18.3.1 version: 18.3.1 @@ -1086,8 +1092,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1122,8 +1128,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tabler/icons-react': specifier: ^3.22.0 version: 3.22.0(react@18.3.1) @@ -1147,8 +1153,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1159,8 +1165,8 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/notifications': - specifier: ^7.14.0 - version: 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tabler/icons-react': specifier: ^3.22.0 version: 3.22.0(react@18.3.1) @@ -1175,8 +1181,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1215,8 +1221,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1237,8 +1243,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1262,8 +1268,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1299,8 +1305,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1324,8 +1330,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1360,20 +1366,20 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) '@mantine/spotlight': - specifier: ^7.14.0 - version: 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tabler/icons-react': specifier: ^3.22.0 version: 3.22.0(react@18.3.1) jotai: - specifier: ^2.10.2 - version: 2.10.2(@types/react@18.3.12)(react@18.3.1) + specifier: ^2.10.3 + version: 2.10.3(@types/react@18.3.12)(react@18.3.1) next: specifier: ^14.2.18 version: 14.2.18(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -1394,8 +1400,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1416,7 +1422,7 @@ importers: version: 4.3.1 mantine-react-table: specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.0.0-beta.7(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: specifier: ^14.2.18 version: 14.2.18(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -1437,8 +1443,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1461,20 +1467,20 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/dates': - specifier: ^7.14.0 - version: 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) '@tabler/icons-react': specifier: ^3.22.0 version: 3.22.0(react@18.3.1) mantine-react-table: specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.0.0-beta.7(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: specifier: ^14.2.18 version: 14.2.18(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -1495,8 +1501,8 @@ importers: specifier: ^1.0.5 version: 1.0.5 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1529,8 +1535,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1589,59 +1595,59 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.14.0 - version: 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mantine/hooks': - specifier: ^7.14.0 - version: 7.14.0(react@18.3.1) + specifier: ^7.14.1 + version: 7.14.1(react@18.3.1) '@tabler/icons-react': specifier: ^3.22.0 version: 3.22.0(react@18.3.1) '@tiptap/extension-color': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/extension-text-style@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/extension-text-style@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))) '@tiptap/extension-highlight': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-image': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-link': - specifier: ^2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) + specifier: ^2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) '@tiptap/extension-table': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) '@tiptap/extension-table-cell': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-table-header': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-table-row': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-task-item': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) '@tiptap/extension-task-list': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-text-align': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-text-style': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/extension-underline': - specifier: 2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + specifier: 2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) '@tiptap/react': - specifier: ^2.9.1 - version: 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^2.10.2 + version: 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tiptap/starter-kit': - specifier: ^2.9.1 - version: 2.9.1 + specifier: ^2.10.2 + version: 2.10.2 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -1650,7 +1656,7 @@ importers: version: 1.11.13 mantine-react-table: specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.0.0-beta.7(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: specifier: ^14.2.18 version: 14.2.18(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -1674,8 +1680,8 @@ importers: specifier: ^7.3.58 version: 7.3.58 eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1687,25 +1693,25 @@ importers: version: 14.2.18 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@9.14.0) + version: 9.1.0(eslint@9.15.0) eslint-config-turbo: - specifier: ^2.3.0 - version: 2.3.0(eslint@9.14.0) + specifier: ^2.3.1 + version: 2.3.1(eslint@9.15.0) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0) + version: 2.31.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.14.0) + version: 6.10.2(eslint@9.15.0) eslint-plugin-react: specifier: ^7.37.2 - version: 7.37.2(eslint@9.14.0) + version: 7.37.2(eslint@9.15.0) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.0.0(eslint@9.14.0) + version: 5.0.0(eslint@9.15.0) typescript-eslint: - specifier: ^8.14.0 - version: 8.14.0(eslint@9.14.0)(typescript@5.6.3) + specifier: ^8.15.0 + version: 8.15.0(eslint@9.15.0)(typescript@5.6.3) devDependencies: '@homarr/prettier-config': specifier: workspace:^0.1.0 @@ -1714,8 +1720,8 @@ importers: specifier: workspace:^0.1.0 version: link:../typescript eslint: - specifier: ^9.14.0 - version: 9.14.0 + specifier: ^9.15.0 + version: 9.15.0 typescript: specifier: ^5.6.3 version: 5.6.3 @@ -1766,8 +1772,8 @@ packages: nodemailer: optional: true - '@auth/core@0.37.3': - resolution: {integrity: sha512-qcffDLwxB9iUYH8GHq68w/KU8jtjAbjjk9xnpoKhjX3+QcntaQ2MKVSkTTocmA6ElpL5vK2xR9CXfQ98dvGnyg==} + '@auth/core@0.37.4': + resolution: {integrity: sha512-HOXJwXWXQRhbBDHlMU0K/6FT1v+wjtzdKhsNg0ZN7/gne6XPsIrjZ4daMcFnbq0Z/vsAbYBinQhhua0d77v7qw==} peerDependencies: '@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/server': ^9.0.2 @@ -1780,8 +1786,8 @@ packages: nodemailer: optional: true - '@auth/drizzle-adapter@1.7.3': - resolution: {integrity: sha512-0BuGgRjcghoFJQH8796BaLCFXqh77lhizXuDliVK7cF2hs1nXo7eKZ/m5ddFa7ATTOwQ3gncQLHFJ1ap8dOoew==} + '@auth/drizzle-adapter@1.7.4': + resolution: {integrity: sha512-OPZQakWWm5Hbx6okVMbtgI08WBliz/dCbFUXiPg9TThpp3Wh7MME/ubg4fW1oOp8P0gul6MkFvMVO733sVtd2w==} '@axiomhq/js@1.0.0-rc.3': resolution: {integrity: sha512-Zm10TczcMLounWqC42nMkXQ7XKLqjzLrd5ia022oBKDUZqAFVg2y9d1quQVNV4FlXyg9MKDdfMjpKQRmzEGaog==} @@ -1962,20 +1968,16 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@ctrl/deluge@6.1.0': - resolution: {integrity: sha512-n8237DbSHlANTLBS3rxIKsnC3peltifJhV2h6fWp5lb7BNZuA3LFz0gVS02aAhj351G3A0ScSYLmuAAL2ld/Nw==} + '@ctrl/deluge@7.0.0': + resolution: {integrity: sha512-9vnBa2UdYKKC8BXMjLB349LiXL98oyhr8lVGmQq/QhT8RtuB9qzVXHsHPnWjZH1nD24dZM/vOvoG46VWRtRghA==} engines: {node: '>=18'} '@ctrl/magnet-link@4.0.2': resolution: {integrity: sha512-wENP7LH4BmCjz+gXVq7Nzz20zMjY/huuG7aDk/yu/LhFdC84e/l8222rCIAo0lwhU451lFcJKLcOmtG6TNrBAQ==} engines: {node: '>=18'} - '@ctrl/qbittorrent@9.0.1': - resolution: {integrity: sha512-MaQhyccZ30C1V8Uxqhc1NvrM/Lgb8x6AunIxjlbhYhw5Zx/l8G2etbjTKle3RIFExURKmzrJx7Odj3EM4AlqDQ==} - engines: {node: '>=18'} - - '@ctrl/shared-torrent@6.0.0': - resolution: {integrity: sha512-BZAPDv8syFArFTAAeb560JSBNTajFtP3G/5eYiUMsg0upGAQs6NWGiHYbyjvAt8uHCSzxXsiji/Wvq1b7CvXSQ==} + '@ctrl/qbittorrent@9.1.0': + resolution: {integrity: sha512-mqro5vP94m/evgGSv6fa7Hrip2fhI0F/dMgsTisvi9gChtfXpX1Cj1EwJNzBOiT6yYamEtLJuEe41XLQiXEo/Q==} engines: {node: '>=18'} '@ctrl/shared-torrent@6.1.0': @@ -2729,28 +2731,28 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.18.0': - resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + '@eslint/config-array@0.19.0': + resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.7.0': - resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + '@eslint/core@0.9.0': + resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.1.0': - resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.14.0': - resolution: {integrity: sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==} + '@eslint/js@9.15.0': + resolution: {integrity: sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.0': - resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==} + '@eslint/plugin-kit@0.2.3': + resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@extractus/feed-extractor@7.1.3': @@ -2837,8 +2839,8 @@ packages: resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} - '@humanwhocodes/retry@0.4.0': - resolution: {integrity: sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==} + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} '@ianvs/prettier-plugin-sort-imports@4.4.0': @@ -2898,71 +2900,71 @@ packages: '@libsql/core@0.14.0': resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} - '@mantine/colors-generator@7.14.0': - resolution: {integrity: sha512-her9frpRgTFaE2kykFAKUPIu38rqiwfetsY5ruGRaqDNRQrNMLoLS02dhapPMNQaJOiBQnE5+aKihGsVB8oVnQ==} + '@mantine/colors-generator@7.14.1': + resolution: {integrity: sha512-WcOyv0HpSmoraZCX2GMJrmNguY4Syaz+hPdSZ6/RaQwOiXdswCZhrYkWjIO+yGKhu0pAD+rsTD0fdLtkFBKT3g==} peerDependencies: chroma-js: '>=2.4.2' - '@mantine/core@7.14.0': - resolution: {integrity: sha512-Osj3nwCXFhOVHIoDtpEpciP7huPhGmG/0w+Zol5tKJ9SG5trV4NDfdFwFcNoxx5al8L6eCLS/fJhloFXaqhOnA==} + '@mantine/core@7.14.1': + resolution: {integrity: sha512-oHqaOE1n4KJkvJgF628OCVXE2zUgkEotEsPUdVaC58qRfJ7SvZAI26JNbUG8+MoqHHEqHKtBaRkTyuEVMbomxw==} peerDependencies: - '@mantine/hooks': 7.14.0 + '@mantine/hooks': 7.14.1 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/dates@7.14.0': - resolution: {integrity: sha512-GXChSxIQi1iFg6Z9t7c2AUuHPDKu2e188MYbUwbVB7EkKSSnSDAs0YxHguF2+uMAKea/u22WyKi/LPdemIyr0w==} + '@mantine/dates@7.14.1': + resolution: {integrity: sha512-NtQWisJi0DmYehShmYvHM6bvUsVE864kW4NJc8rbatFL7/bhCp9U49s6vqpz6B1GxZ2WfiQZtjPE1FLInWX+Pw==} peerDependencies: - '@mantine/core': 7.14.0 - '@mantine/hooks': 7.14.0 + '@mantine/core': 7.14.1 + '@mantine/hooks': 7.14.1 dayjs: '>=1.0.0' react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/form@7.14.0': - resolution: {integrity: sha512-oZQuSiREcZLALTILUwovIc1GuNSQAZfFyhUCQE2MqF5tmjcy51HdeQ0kBtkjCylrc50v165KVtANuWhFwA/2dg==} + '@mantine/form@7.14.1': + resolution: {integrity: sha512-ziYsTsFhR1sEjGebwahKr7LRRFQQtH47o+rPLbvD0FGb6aYRVQgaebQo4jVgxFIgqiafxGNEpD6GkPBqmCmU4g==} peerDependencies: react: ^18.x || ^19.x - '@mantine/hooks@7.14.0': - resolution: {integrity: sha512-BJ577AoQ5KnvbuaG174TYAmL2UqcX9qh9aL0aOx+gqyMM6GWeBXUXWx1kcMCzaDbYZwfQptU476fpSjHdcLjMw==} + '@mantine/hooks@7.14.1': + resolution: {integrity: sha512-VlgTyV/9WNFCwCshW1KHMYNzLt+M8aG68E1lWaqOXtyWSLJo+X5zQJGg0f8bwGbJvIMQCpQd0yTLfnjD6uAtrA==} peerDependencies: react: ^18.x || ^19.x - '@mantine/modals@7.14.0': - resolution: {integrity: sha512-+9NeQnvH3dARoPXqJyq68FUt8+YWf/n1iNGM6ssbysrK2RMRZd/+XjdhRwGVi464Lg4UUT/QKbMos9CGrNxj9A==} + '@mantine/modals@7.14.1': + resolution: {integrity: sha512-jpcRS5fzD+CPRJ7mebA9lt0bmSI+2lJVZloG7SPIY3S66ZtUsEis0fHkDtuAqGANbhr43Enjhno0M+4x9IzuZw==} peerDependencies: - '@mantine/core': 7.14.0 - '@mantine/hooks': 7.14.0 + '@mantine/core': 7.14.1 + '@mantine/hooks': 7.14.1 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/notifications@7.14.0': - resolution: {integrity: sha512-CEpGRYj7xtzYQ8VLHN+tespWkTH3U1ghHKxKeJNmfcSjf7VcMbTa0LlKgszUE6A4CZma32RsxhDXdvgcQ3xmUg==} + '@mantine/notifications@7.14.1': + resolution: {integrity: sha512-08suBIh/EJuTnzF1/Aao73S534KXvD7MiEaRNPXG+vBFz57Lu4DOtyLG4mXju6eNK99KJziVlK7CMIv6ADcQNg==} peerDependencies: - '@mantine/core': 7.14.0 - '@mantine/hooks': 7.14.0 + '@mantine/core': 7.14.1 + '@mantine/hooks': 7.14.1 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/spotlight@7.14.0': - resolution: {integrity: sha512-/Xcjj6eGtOVw7Dj+O+bpSiYXRJiepQtyXxFoNrFTB39AAdxf8psd8Um1iC60YGXa+VRYocU8uWu0yP3D1hT7FQ==} + '@mantine/spotlight@7.14.1': + resolution: {integrity: sha512-yQ7ROtlxn1KclEtPs8RN+yUvkwopvXvM2qqjKrDa/XtvugjYICcJzyop4W+uzddekrlk55Y0qaSAzMBUpqZg/w==} peerDependencies: - '@mantine/core': 7.14.0 - '@mantine/hooks': 7.14.0 + '@mantine/core': 7.14.1 + '@mantine/hooks': 7.14.1 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/store@7.14.0': - resolution: {integrity: sha512-qI0XnQZkHuWYbe9Mn6kFObka4x26RINnDpyJGSiK6on+VwDWGJ3gn1dfFlQa2zboVtA6OUXHyxDlwALHNJwiZw==} + '@mantine/store@7.14.1': + resolution: {integrity: sha512-wpemDaqOJc1zsvnjaic1+KRQSy7dZhQ4XDwxqqq5MwG6aImCHqEBVf17Qhj3sDjpA7pnpxnKAHotLqfzjQn3dQ==} peerDependencies: react: ^18.x || ^19.x - '@mantine/tiptap@7.14.0': - resolution: {integrity: sha512-z6dB6buVYlOSnEcq02otePs/JlIs67iOAaSDe8zC1w1MzxgX4R0DNUq/KutoqpqjonowRpYOrLj6nv9RcRrAmg==} + '@mantine/tiptap@7.14.1': + resolution: {integrity: sha512-pwhvR1Om8XOD6QCDWUdWKyq/djV0Gm2Z5HjziDkAJtiUfj5IWkxPinAF7lkV/9XDafo4oa3hyOA6XegdInE0rw==} peerDependencies: - '@mantine/core': 7.14.0 - '@mantine/hooks': 7.14.0 + '@mantine/core': 7.14.1 + '@mantine/hooks': 7.14.1 '@tiptap/extension-link': '>=2.1.12' '@tiptap/react': '>=2.1.12' react: ^18.x || ^19.x @@ -3384,27 +3386,27 @@ packages: resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} engines: {node: '>=12'} - '@tanstack/query-core@5.60.5': - resolution: {integrity: sha512-jiS1aC3XI3BJp83ZiTuDLerTmn9P3U95r6p+6/SNauLJaYxfIC4dMuWygwnBHIZxjn2zJqEpj3nysmPieoxfPQ==} + '@tanstack/query-core@5.60.6': + resolution: {integrity: sha512-tI+k0KyCo1EBJ54vxK1kY24LWj673ujTydCZmzEZKAew4NqZzTaVQJEuaG1qKj2M03kUHN46rchLRd+TxVq/zQ==} '@tanstack/query-devtools@5.59.20': resolution: {integrity: sha512-vxhuQ+8VV4YWQSFxQLsuM+dnEKRY7VeRzpNabFXdhEwsBYLrjXlF1pM38A8WyKNLqZy8JjyRO8oP4Wd/oKHwuQ==} - '@tanstack/react-query-devtools@5.60.5': - resolution: {integrity: sha512-lzANl0ih3CNKBGUoXhhkAAHI1Y4Yqs9Jf3iuTUsGiPpmF0RWXTeYFaQxc+h1PhJz3VwYrIYCwmPoNts0mSjSuA==} + '@tanstack/react-query-devtools@5.61.0': + resolution: {integrity: sha512-hd3yXl+KV+OGQmAw946qHAFp6DygcXcYN+1ai9idYddx6uEQyCwYk3jyIBOQEUw9uzN5DOGJLBsgd/QcimDQsA==} peerDependencies: - '@tanstack/react-query': ^5.60.5 + '@tanstack/react-query': ^5.61.0 react: ^18 || ^19 - '@tanstack/react-query-next-experimental@5.60.5': - resolution: {integrity: sha512-AcM9/seS7Oq/E50QrtqSwYaExylkkwup3BsrdRwGIIRSaUmpWGG9damTfX005zd3sCor4LxEbxnebdks0wO5iw==} + '@tanstack/react-query-next-experimental@5.61.0': + resolution: {integrity: sha512-jR1KHeeUgj/Dec5P/cWZF4hx6I9KS+NWfjlwS3PWdoJKBn6OKWqn4na/pFsPk1KNZVcNv+C9pHxBBY3/gU48nQ==} peerDependencies: - '@tanstack/react-query': ^5.60.5 + '@tanstack/react-query': ^5.61.0 next: ^13 || ^14 || ^15 react: ^18 || ^19 - '@tanstack/react-query@5.60.5': - resolution: {integrity: sha512-M77bOsPwj1wYE56gk7iJvxGAr4IC12NWdIDhT+Eo8ldkWRHMvIR8I/rufIvT1OXoV/bl7EECwuRuMlxxWtvW2Q==} + '@tanstack/react-query@5.61.0': + resolution: {integrity: sha512-SBzV27XAeCRBOQ8QcC94w2H1Md0+LI0gTWwc3qRJoaGuewKn5FNW4LSqwPFJZVEItfhMfGT7RpZuSFXjTi12pQ==} peerDependencies: react: ^18 || ^19 @@ -3428,203 +3430,203 @@ packages: '@tanstack/virtual-core@3.10.8': resolution: {integrity: sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==} - '@testcontainers/mysql@10.14.0': - resolution: {integrity: sha512-6OzI1a7jRn+JvuDHv4v7hbMHg9A6ID7/svKiKXS3m8xNkfbOvyznNi06O7pBMLlfRugqfZE0o9WdRIRXxWTkKw==} + '@testcontainers/mysql@10.15.0': + resolution: {integrity: sha512-YxAPlsigvjq0EPKbQuaPyQVgEa8nNIw2TPbtq7MyZh1eG3ePHKvpqEmDAu7GsfgJqYZU3YvK5b8Ty9Wo0qJYNA==} - '@tiptap/core@2.9.1': - resolution: {integrity: sha512-tifnLL/ARzQ6/FGEJjVwj9UT3v+pENdWHdk9x6F3X0mB1y0SeCjV21wpFLYESzwNdBPAj8NMp8Behv7dBnhIfw==} + '@tiptap/core@2.10.2': + resolution: {integrity: sha512-jYLXbYHTi1stLla/74J8NJizDtcJ/uokhG+1gN4DMWHDujaZOrRZhW98o9gN5BYAp4zv//TVX8H+afLZwKGCKQ==} peerDependencies: '@tiptap/pm': ^2.7.0 - '@tiptap/extension-blockquote@2.9.1': - resolution: {integrity: sha512-Y0jZxc/pdkvcsftmEZFyG+73um8xrx6/DMfgUcNg3JAM63CISedNcr+OEI11L0oFk1KFT7/aQ9996GM6Kubdqg==} + '@tiptap/extension-blockquote@2.10.2': + resolution: {integrity: sha512-whmep+v0VvBI9Kg5TJ4sKIj7Z+MOjBKAndP0qn1bMoqPNNVRxt92iIud72wfXwfBNcrYiGNlssvsAnPwXfbG9w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bold@2.9.1': - resolution: {integrity: sha512-e2P1zGpnnt4+TyxTC5pX/lPxPasZcuHCYXY0iwQ3bf8qRQQEjDfj3X7EI+cXqILtnhOiviEOcYmeu5op2WhQDg==} + '@tiptap/extension-bold@2.10.2': + resolution: {integrity: sha512-1KNTXA8HDkhXblkfeRYDdqAu/Xz2fygyaSrvabrfzg5QVYyVYPNJwjrtfTQNyzWOejBVGE3mOyqnjlLUzPmyYA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bubble-menu@2.9.1': - resolution: {integrity: sha512-DWUF6NG08/bZDWw0jCeotSTvpkyqZTi4meJPomG9Wzs/Ol7mEwlNCsCViD999g0+IjyXFatBk4DfUq1YDDu++Q==} + '@tiptap/extension-bubble-menu@2.10.2': + resolution: {integrity: sha512-KAh2bvYcixJ3RFv2P05kPNLAJ4uW6BDj1AfEMn0YguBWWTgZg8Kot1AzBRgTjBBFCInQS6b49db1ff4M07DGsg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-bullet-list@2.9.1': - resolution: {integrity: sha512-0hizL/0j9PragJObjAWUVSuGhN1jKjCFnhLQVRxtx4HutcvS/lhoWMvFg6ZF8xqWgIa06n6A7MaknQkqhTdhKA==} + '@tiptap/extension-bullet-list@2.10.2': + resolution: {integrity: sha512-jXtTQXZ3j2cyG2dNyVnGauIbsX8CmDY56MJfDg1p+1UZ3zW2GVbKHfvyuulsjobxEd0DNLxduGqbkDY7x3I+HA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-code-block@2.9.1': - resolution: {integrity: sha512-A/50wPWDqEUUUPhrwRKILP5gXMO5UlQ0F6uBRGYB9CEVOREam9yIgvONOnZVJtszHqOayjIVMXbH/JMBeq11/g==} + '@tiptap/extension-code-block@2.10.2': + resolution: {integrity: sha512-Y/wkK9Ni4ALGqiGezov62p6cpPcJauBfn2wF1lgJVr6XJ4na5KTCUEbiyBZNbo3aD52vZKgWt8LpLvJ2/5STSw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-code@2.9.1': - resolution: {integrity: sha512-WQqcVGe7i/E+yO3wz5XQteU1ETNZ00euUEl4ylVVmH2NM4Dh0KDjEhbhHlCM0iCfLUo7jhjC7dmS+hMdPUb+Tg==} + '@tiptap/extension-code@2.10.2': + resolution: {integrity: sha512-VV14oeOsJ3VqUEjuUl+lzSW/IBLhurmcj9IiN2sq/Voin04dwvtchqP5fNXgmM3+rFM88zNOsbX0e4uSG4R10w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-color@2.9.1': - resolution: {integrity: sha512-9h4FcCDenOmr8x8/Vfzg9PBYrgXIXTi2x8JiaTbrQX+Ufea1SMx+Ko/Vowp7SGMnBAsB+sXkTVhAhiXDQbtWcQ==} + '@tiptap/extension-color@2.10.2': + resolution: {integrity: sha512-lIUrsk8XBG0h8ft5vU6u0ehPk0pcZK3xjhOLF/qxiGhZNBynX5/Nb7mez05J0/P6GKsD9Hj6UD7wm4ZkGmNT9A==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-document@2.9.1': - resolution: {integrity: sha512-1a+HCoDPnBttjqExfYLwfABq8MYdiowhy/wp8eCxVb6KGFEENO53KapstISvPzqH7eOi+qRjBB1KtVYb/ZXicg==} + '@tiptap/extension-document@2.10.2': + resolution: {integrity: sha512-Xodp6rMg6vtKZkyX3I6gVd6OZ9PNz9udhDLdCG6JscVJQPO8viV++39UOH416FCvRT46BdHWNCRu/xjUG1C0rA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-dropcursor@2.9.1': - resolution: {integrity: sha512-wJZspSmJRkDBtPkzFz1g7gvZOEOayk8s93UHsgbJxcV4VWHYleZ5XhT74sZunSjefNDm3qC6v2BSgLp3vNHVKQ==} + '@tiptap/extension-dropcursor@2.10.2': + resolution: {integrity: sha512-pzkD6Y9r3x4Mb6KqpuPraGNNfxIkQD6dJNtZ9PpU9jVtJDjsGIGdyzCbVJq984UAPBamXiF/5DLwlON7buLd6A==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-floating-menu@2.9.1': - resolution: {integrity: sha512-MxZ7acNNsoNaKpetxfwi3Z11Bgrh0T2EJlCV77v9N1vWK38+st3H1WJanmLbPNtc2ocvhHJrz+DjDz3CWxQ9rQ==} + '@tiptap/extension-floating-menu@2.10.2': + resolution: {integrity: sha512-s/KfW5YQY13BwhSQRlgomYmHuBT0k6FBxn8mgJLHcA9sTqgy/BriOhmNkMrredNzd4UOd5JVpcT6b+eckG4nkQ==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-gapcursor@2.9.1': - resolution: {integrity: sha512-jsRBmX01vr+5H02GljiHMo0n5H1vzoMLmFarxe0Yq2d2l9G/WV2VWX2XnGliqZAYWd1bI0phs7uLQIN3mxGQTw==} + '@tiptap/extension-gapcursor@2.10.2': + resolution: {integrity: sha512-Uj2hIYC5zRPGI9xBYFwtld8JrZ8YZXEqO7sN5VcOwt12cnSmvzga86jUKpj3WOMP/8KamLWW8m8UKHd7Qg1kMA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-hard-break@2.9.1': - resolution: {integrity: sha512-fCuaOD/b7nDjm47PZ58oanq7y4ccS2wjPh42Qm0B0yipu/1fmC8eS1SmaXmk28F89BLtuL6uOCtR1spe+lZtlQ==} + '@tiptap/extension-hard-break@2.10.2': + resolution: {integrity: sha512-jEVKEe8I+Ai/qYjVf6Idg2Gpp1Cxn4O4twJ0MnlEdzoaEHgt/OTU5NO0PBZMpoe/4BkOvkETZmqRbrcGsapeYQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-heading@2.9.1': - resolution: {integrity: sha512-SjZowzLixOFaCrV2cMaWi1mp8REK0zK1b3OcVx7bCZfVSmsOETJyrAIUpCKA8o60NwF7pwhBg0MN8oXlNKMeFw==} + '@tiptap/extension-heading@2.10.2': + resolution: {integrity: sha512-OfvE+epZSyB0TbV5/4GdvRPMT1kd0fbgLUEaldWMZOLw/4eOGWZ8yXAtrWkoRMLZfOclgnDfwXvXJLnWXrDdDw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-highlight@2.9.1': - resolution: {integrity: sha512-ro3bARRgxb4v8w6fPVfG1kO2UWtLgKI5ESfsQ9CqiZuRkZdRKhM5ZpXPIky28Pn7CxhDUSXBXS/MhvP0VuhMJQ==} + '@tiptap/extension-highlight@2.10.2': + resolution: {integrity: sha512-yJpqagUS672RPsGRc6JrNuqf3DbMiP+g4Al3cVpU3ff3yEORbCMsgvwkCOE9thSO9B4SOFQP4HzX2x1DLJtjew==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-history@2.9.1': - resolution: {integrity: sha512-wp9qR1NM+LpvyLZFmdNaAkDq0d4jDJ7z7Fz7icFQPu31NVxfQYO3IXNmvJDCNu8hFAbImpA5aG8MBuwzRo0H9w==} + '@tiptap/extension-history@2.10.2': + resolution: {integrity: sha512-Hr5cvYgOAP7vaRD5vbMjirTATFe/zYqnzePhq1c9TQESOi2o0zKxWpZIcHbFFIXCjHLSnpXOZ4yFwHP4k12rgg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-horizontal-rule@2.9.1': - resolution: {integrity: sha512-ydUhABeaBI1CoJp+/BBqPhXINfesp1qMNL/jiDcMsB66fsD4nOyphpAJT7FaRFZFtQVF06+nttBtFZVkITQVqg==} + '@tiptap/extension-horizontal-rule@2.10.2': + resolution: {integrity: sha512-DqaCUxjXnoVN/yylEjoGIlvKkT1KF8mwFJncJn8oSAukYEaSAK056ETvmyZk+/bzc3aRpfv0Kfn/zmLfHZ3wnA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-image@2.9.1': - resolution: {integrity: sha512-aGqJnsuS8oagIhsx7wetm8jw4NEDsOV0OSx4FQ4VPlUqWlnzK0N+erFKKJmXTdAxL8PGzoPSlITFH63MV3eV3Q==} + '@tiptap/extension-image@2.10.2': + resolution: {integrity: sha512-xaJOVeR/fWozJMVKjYhskecsbayUUm1tIbjE+SyG7IW3Jp+081/W9z2nyfXG6YNnuVjYq+uLejR2Bt0cnEZvmA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-italic@2.9.1': - resolution: {integrity: sha512-VkNA6Vz96+/+7uBlsgM7bDXXx4b62T1fDam/3UKifA72aD/fZckeWrbT7KrtdUbzuIniJSbA0lpTs5FY29+86Q==} + '@tiptap/extension-italic@2.10.2': + resolution: {integrity: sha512-6p1YkJEWHuMROzNrK+GFJamujBswpydfR3ZMpIjQTLr4hRhSGrde/B5WODRDS+3JiK1xcN16ZQVPFsRJaHMjfQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-link@2.9.1': - resolution: {integrity: sha512-yG+e3e8cCCN9dZjX4ttEe3e2xhh58ryi3REJV4MdiEkOT9QF75Bl5pUbMIS4tQ8HkOr04QBFMHKM12kbSxg1BA==} + '@tiptap/extension-link@2.10.2': + resolution: {integrity: sha512-bgsWdinDPGEiMD0NgphpKaxm4l9+PbPwdLDGDFyEX069VAyuSN4y63Sn32clpwlLcibVu3JxVFClJ+o6wKtmdg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-list-item@2.9.1': - resolution: {integrity: sha512-6O4NtYNR5N2Txi4AC0/4xMRJq9xd4+7ShxCZCDVL0WDVX37IhaqMO7LGQtA6MVlYyNaX4W1swfdJaqrJJ5HIUw==} + '@tiptap/extension-list-item@2.10.2': + resolution: {integrity: sha512-NE800m/QCk58MUcfeeCqmDjgOuiwHddaZvCCQIpErZdI2Y0io9RsSYU3HHEFPIfbKsv/ykVTYbwSweTPs1Tmxw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-ordered-list@2.9.1': - resolution: {integrity: sha512-6J9jtv1XP8dW7/JNSH/K4yiOABc92tBJtgCsgP8Ep4+fjfjdj4HbjS1oSPWpgItucF2Fp/VF8qg55HXhjxHjTw==} + '@tiptap/extension-ordered-list@2.10.2': + resolution: {integrity: sha512-1WYknf7/feouoBN7jW9Z6fvN9gzS1WRaOrDVkLZQ2ZLgT+Bs8H8/r1pv23q8Un6lg0mApwqnUxNhLOOrVyDkGQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-paragraph@2.9.1': - resolution: {integrity: sha512-JOmT0xd4gd3lIhLwrsjw8lV+ZFROKZdIxLi0Ia05XSu4RLrrvWj0zdKMSB+V87xOWfSB3Epo95zAvnPox5Q16A==} + '@tiptap/extension-paragraph@2.10.2': + resolution: {integrity: sha512-EZG9W5rsU4uP585cIOrhbAPOUsgqrFbDrj1tZjTbvv0EWK03Un3FGYoGilkcUIxD9uB/XVHP+v2596Ifyi/dvQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-strike@2.9.1': - resolution: {integrity: sha512-V5aEXdML+YojlPhastcu7w4biDPwmzy/fWq0T2qjfu5Te/THcqDmGYVBKESBm5x6nBy5OLkanw2O+KHu2quDdg==} + '@tiptap/extension-strike@2.10.2': + resolution: {integrity: sha512-TjrBbO6UbXCt55hV9wRE7h5R/jLTB+z2yn2blz1TfR7wKkX3tJOnb+ptvIHEVFGJOjkZP6Xaj+aAkGVg5dKZYA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-cell@2.9.1': - resolution: {integrity: sha512-/wrcniLdhMhs5M2NDetFcfq510N5to7YKK+52KOXNotBI8K/GjMmGmtwWEKPITD0/RgYrXzpMcta/O+/0OCOPQ==} + '@tiptap/extension-table-cell@2.10.2': + resolution: {integrity: sha512-FmppE53gmg/PTdtxAMsGP13SZc03dVKsH94l/Jj60gU5xPnjR6424+SETdotjAQdFCBRTYoci2BCP+22e/FTzw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-header@2.9.1': - resolution: {integrity: sha512-KtI01636Du1IB/I3pe9ZJWKkOc6INqAaIw+RFirRCnd8Xnik7tJfAwdhXzoPRcer6ViZmlzSrM2dkwaZCF7gcw==} + '@tiptap/extension-table-header@2.10.2': + resolution: {integrity: sha512-1kmWgKrrHSC38sB+IWwYnBmRFot8u3PntneHIpQoo11wcVkEWUNZ9lmhEKMawnKan5h2yDVlUsPMR9QB/iarsQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-row@2.9.1': - resolution: {integrity: sha512-Wq7QlI/S5iX4UCAdX+ok/szegVMbvrM3H8o6jwO+G4p8JJt6iv7ZmEnJ19xIINhmiKsrdanqH9FFK4tQ3yvQ0A==} + '@tiptap/extension-table-row@2.10.2': + resolution: {integrity: sha512-htS8ld4HD0zl7g0C/V9szdAX8Cjz9+ckr8qGrJy6yJS9ByS2x0VnV5fT73WUCx0zlNOrr1hcedlvDUTEPvzSuQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table@2.9.1': - resolution: {integrity: sha512-OmWZFZOSZwSSEvoVUkDsRFyCXTYei/pV396Xjv9pfFzXQkVbfq/CjTp61zvb/9mmEz3rcfvfG7G39eRlZTvBNg==} + '@tiptap/extension-table@2.10.2': + resolution: {integrity: sha512-T7hzHEB090KsAy0VS4wogcjwauKHlYorQKrBxxZHzE6n6w6Zi0Cz00qJnAb6oYgKrMCTredcxnWUH8PmWlehYg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-task-item@2.9.1': - resolution: {integrity: sha512-nao7lg7MF6DXc8N7K2yP9Y6Gb8113cVSEIXxy6PU9oMgXp0xSzIL2pkG1E2bgSqkUIop1pHzeF4cNLMY+MO2fg==} + '@tiptap/extension-task-item@2.10.2': + resolution: {integrity: sha512-FArCQ+j3QYwF6CbexkRJUPTgfMsFJ3uYCFHtJFQbMp8KqGHh19R3Rvc+Z4PFHX3SD6dbBcSQFoiL2mUTKFj8XA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-task-list@2.9.1': - resolution: {integrity: sha512-vmUkclPi02iVf+uu74iyUp5xGNib0Gxs73DJ1z+a7CzjuLRqqCa/KEde95CR0Y//DaK/Csz4DOSUyTfLCMvpWg==} + '@tiptap/extension-task-list@2.10.2': + resolution: {integrity: sha512-q4FJGjYL2n34XyjC/k9C1Fyx0M4DavyNLq0v3Gqa9/exZD6d4uUYHUHcFvZXOBYrkpVh+4fxIOQvcyz54WVKYw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-align@2.9.1': - resolution: {integrity: sha512-oUp0XnwJpAImcOVV68vsY2CpkHpRZ3gzWfIRTuy+aYitQim3xDKis/qfWQUWZsANp9/TZ0VyjtkZxNMwOfcu1g==} + '@tiptap/extension-text-align@2.10.2': + resolution: {integrity: sha512-eDvks4fUZuOuAhWD8/HJ070g2OQlEnBpak2+huvzPhGdYP81vhx5OWk/rfF6WzLzxLwnDND2zvk3YL+RBqERZQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-style@2.9.1': - resolution: {integrity: sha512-LAxc0SeeiPiAVBwksczeA7BJSZb6WtVpYhy5Esvy9K0mK5kttB4KxtnXWeQzMIJZQbza65yftGKfQlexf/Y7yg==} + '@tiptap/extension-text-style@2.10.2': + resolution: {integrity: sha512-dWx5Ean7Rb6rdqO6C/i0qIIABKHFsABZj0mTDr0/ZXsw3V2O4d1cP13evvcc7HMLNAXziRTtWCVU6M06vwM/Pw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text@2.9.1': - resolution: {integrity: sha512-3wo9uCrkLVLQFgbw2eFU37QAa1jq1/7oExa+FF/DVxdtHRS9E2rnUZ8s2hat/IWzvPUHXMwo3Zg2XfhoamQpCA==} + '@tiptap/extension-text@2.10.2': + resolution: {integrity: sha512-7WaJCmHAnf24gZc+Bl64vZgjAFt0CSEc5Jr+f3GII6XeCkZpTCJX85po2MFUhBRZMJheyctyL+UfsRauo/iP0Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-underline@2.9.1': - resolution: {integrity: sha512-IrUsIqKPgD7GcAjr4D+RC0WvLHUDBTMkD8uPNEoeD1uH9t9zFyDfMRPnx/z3/6Gf6fTh3HzLcHGibiW2HiMi2A==} + '@tiptap/extension-underline@2.10.2': + resolution: {integrity: sha512-jDWGqqUYkrLgqRQDyqh+LpbkiqPfaWOoo5bydYL0u80GPEavovxZPoCJ/HDlOfdwm+FIPy55OP/29tELJRptmg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/pm@2.9.1': - resolution: {integrity: sha512-mvV86fr7kEuDYEApQ2uMPCKL2uagUE0BsXiyyz3KOkY1zifyVm1fzdkscb24Qy1GmLzWAIIihA+3UHNRgYdOlQ==} + '@tiptap/pm@2.10.2': + resolution: {integrity: sha512-jEgC79uvuEl51XxulutUJPSlhkoY0xQc9R/G4MQltAi+JxJ+KE/pOxgqziWNxBpgUzQqloupjod0kLhLUL4Cig==} - '@tiptap/react@2.9.1': - resolution: {integrity: sha512-LQJ34ZPfXtJF36SZdcn4Fiwsl2WxZ9YRJI87OLnsjJ45O+gV/PfBzz/4ap+LF8LOS0AbbGhTTjBOelPoNm+aYA==} + '@tiptap/react@2.10.2': + resolution: {integrity: sha512-xBg0uA/ON9LbC8ojwjgFQgZA1xmaEotXZnZcM3tfGjCboqk0toi59v+2CIN9icDfW+UT/hsget3SBQtRw+SBEw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.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@2.9.1': - resolution: {integrity: sha512-nsw6UF/7wDpPfHRhtGOwkj1ipIEiWZS1VGw+c14K61vM1CNj0uQ4jogbHwHZqN1dlL5Hh+FCqUHDPxG6ECbijg==} + '@tiptap/starter-kit@2.10.2': + resolution: {integrity: sha512-YbS9P3zvLhfEWnCPMcvCwK/+3XjMgZX73D1qMu9jVRHtQGI2DMk9u42KWAMLQAMBUESMcIeGxJ9G5IWJO0PsyA==} '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -3677,12 +3679,12 @@ packages: '@tsconfig/svelte@1.0.13': resolution: {integrity: sha512-5lYJP45Xllo4yE/RUBccBT32eBlRDbqN8r1/MIvQbKxW3aFqaYPCNgm8D5V20X4ShHcwvYWNlKg3liDh1MlBoA==} - '@turbo/gen@2.3.0': - resolution: {integrity: sha512-H0ktAVBm8bbngQvklOOBDEIXqSII1Ok0SYy6wUu7UTR81KwDumXtnCi5xUhSHzv4UCF+Gvkle8Fol1ge8ZD/Lg==} + '@turbo/gen@2.3.1': + resolution: {integrity: sha512-QlxmNhrgH9vkI8e13O3Wd3wnLLb+JbGBeifaYywORN9bY29YmObhxLvBTCYGoYFED1nHRxB19mTJBQjPdejskA==} hasBin: true - '@turbo/workspaces@2.3.0': - resolution: {integrity: sha512-j7iexvpBIRK0J9TAVl8g0EcY2Ph5HjzKa0cWKGuGbrYUJ0Ow2X0l6M42uh6CzXwLKTQLw/i+wDAc3f2qBEU5xw==} + '@turbo/workspaces@2.3.1': + resolution: {integrity: sha512-JIDt9G43l/HMOeZcbllbfq7Z8S+GEcjLC9tZS18fs0JQqKsd3lgCJebNS4tJM+3pplJVcM4CQv4BMQxoFW7Qsw==} hasBin: true '@types/asn1@0.2.4': @@ -3706,8 +3708,8 @@ packages: '@types/bcrypt@5.0.2': resolution: {integrity: sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==} - '@types/better-sqlite3@7.6.11': - resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} + '@types/better-sqlite3@7.6.12': + resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -3733,8 +3735,8 @@ packages: '@types/docker-modem@3.0.6': resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - '@types/dockerode@3.3.31': - resolution: {integrity: sha512-42R9eoVqJDSvVspV89g7RwRqfNExgievLNWoHkg7NoWIqAmavIbgQBb4oc0qRtHkxE+I3Xxvqv7qVXFABKPBTg==} + '@types/dockerode@3.3.32': + resolution: {integrity: sha512-xxcG0g5AWKtNyh7I7wswLdFvym4Mlqks5ZlKzxEUrGHS0r0PUOfxm2T0mspwu10mHQqu3Ck3MI3V2HqvLWE1fg==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -3769,6 +3771,15 @@ packages: '@types/keygrip@1.0.6': resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -3781,8 +3792,8 @@ packages: '@types/node@18.19.50': resolution: {integrity: sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==} - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/node@22.9.1': + resolution: {integrity: sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==} '@types/prismjs@1.26.5': resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} @@ -3850,8 +3861,8 @@ packages: '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} - '@typescript-eslint/eslint-plugin@8.14.0': - resolution: {integrity: sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==} + '@typescript-eslint/eslint-plugin@8.15.0': + resolution: {integrity: sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -3861,8 +3872,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.14.0': - resolution: {integrity: sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==} + '@typescript-eslint/parser@8.15.0': + resolution: {integrity: sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -3871,40 +3882,45 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@8.14.0': - resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==} + '@typescript-eslint/scope-manager@8.15.0': + resolution: {integrity: sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.14.0': - resolution: {integrity: sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@8.14.0': - resolution: {integrity: sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.14.0': - resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@8.14.0': - resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==} + '@typescript-eslint/type-utils@8.15.0': + resolution: {integrity: sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true - '@typescript-eslint/visitor-keys@8.14.0': - resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==} + '@typescript-eslint/types@8.15.0': + resolution: {integrity: sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.15.0': + resolution: {integrity: sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@8.15.0': + resolution: {integrity: sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/visitor-keys@8.15.0': + resolution: {integrity: sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@umami/node@0.4.0': @@ -4609,10 +4625,6 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} @@ -4673,6 +4685,14 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + cross-spawn@7.0.5: + resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} + engines: {node: '>= 8'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} @@ -4878,8 +4898,8 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} - dotenv-cli@7.4.2: - resolution: {integrity: sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==} + dotenv-cli@7.4.4: + resolution: {integrity: sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==} hasBin: true dotenv-expand@10.0.0: @@ -4902,15 +4922,15 @@ packages: resolution: {integrity: sha512-JimOV+ystXTWMgZkLHYHf2w3oS28hxiH1FR0dkmJLc7GHzdGJoJAQtQS5DRppnabsRZwE2U1F6CuezVBgmsBBQ==} hasBin: true - drizzle-orm@0.36.3: - resolution: {integrity: sha512-ffQB7CcyCTvQBK6xtRLMl/Jsd5xFTBs+UTHrgs1hbk68i5TPkbsoCPbKEwiEsQZfq2I7VH632XJpV1g7LS2H9Q==} + drizzle-orm@0.36.4: + resolution: {integrity: sha512-1OZY3PXD7BR00Gl61UUOFihslDldfH4NFRH2MbP54Yxi0G/PKn4HfO65JYZ7c16DeP3SpM3Aw+VXVG9j6CRSXA==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=3' '@electric-sql/pglite': '>=0.2.0' '@libsql/client': '>=0.10.0' '@libsql/client-wasm': '>=0.10.0' - '@neondatabase/serverless': '>=0.1' + '@neondatabase/serverless': '>=0.10.0' '@op-engineering/op-sqlite': '>=2' '@opentelemetry/api': ^1.4.1 '@planetscale/database': '>=1' @@ -5142,8 +5162,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-config-turbo@2.3.0: - resolution: {integrity: sha512-Nm9WZgNoUIJw4bpYQugGCDjzYy1TlUD4sQ/nGblL+HdNqJWCj5NqXbJ1k+TBfYedhr65dlGoAFPYUOfjUOmKVg==} + eslint-config-turbo@2.3.1: + resolution: {integrity: sha512-pxxCLLgnZYCjJoGrzUu3jAcb67bKVykLblyMtgTzHN7DlNu6tnp89K3/5fznc6ALyXwXFp0K+nM+Sxst43oaoA==} peerDependencies: eslint: '>6.6.0' @@ -5199,8 +5219,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-plugin-turbo@2.3.0: - resolution: {integrity: sha512-2iVUoIhrjp6kI8p0J4NewKPpXaKrHvL4K4eRnNXbqZvP/7xsm4Of+33B3b7m7OsS0UgX8HHOjlB9bEjigKMkMA==} + eslint-plugin-turbo@2.3.1: + resolution: {integrity: sha512-M5MBYBkcQsv11MFHJ+6WpzLpiTBx0OApeUMAHlO4L0eHqQxY03GrmHXjXfozqB+9HwGrW9fqihBzVRllyixJDA==} peerDependencies: eslint: '>6.6.0' @@ -5220,8 +5240,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.14.0: - resolution: {integrity: sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==} + eslint@9.15.0: + resolution: {integrity: sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -6010,8 +6030,8 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} - jotai@2.10.2: - resolution: {integrity: sha512-DqsBTlRglIBviuJLfK6JxZzpd6vKfbuJ4IqRCz70RFEDeZf46Fcteb/FXxNr1UnoxR5oUy3oq7IE8BrEq0G5DQ==} + jotai@2.10.3: + resolution: {integrity: sha512-Nnf4IwrLhNfuz2JOQLI0V/AgwcpxvVy8Ec8PidIIDeRi4KCFpwTFIpHAAcU+yCgnw/oASYElq9UY0YdUUegsSA==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=17.0.0' @@ -6592,9 +6612,6 @@ packages: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} - ofetch@1.3.4: - resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==} - ofetch@1.4.1: resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} @@ -6889,8 +6906,8 @@ packages: prosemirror-collab@1.3.1: resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} - prosemirror-commands@1.6.0: - resolution: {integrity: sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==} + prosemirror-commands@1.6.2: + resolution: {integrity: sha512-0nDHH++qcf/BuPLYvmqZTUUsPJUCPBUXt0J1ErTcDIS369CTp773itzLGIgIXG4LJXOlwYCr44+Mh4ii6MP1QA==} prosemirror-dropcursor@1.8.1: resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} @@ -6907,14 +6924,14 @@ packages: prosemirror-keymap@1.2.2: resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} - prosemirror-markdown@1.13.0: - resolution: {integrity: sha512-UziddX3ZYSYibgx8042hfGKmukq5Aljp2qoBiJRejD/8MH70siQNz5RB1TrdTPheqLMy4aCe4GYNF10/3lQS5g==} + prosemirror-markdown@1.13.1: + resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} prosemirror-menu@1.2.4: resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} - prosemirror-model@1.22.3: - resolution: {integrity: sha512-V4XCysitErI+i0rKFILGt/xClnFJaohe/wrrlT2NSZ+zk8ggQfDH4x2wNK7Gm0Hp4CIoWizvXFP7L9KMaCuI0Q==} + prosemirror-model@1.23.0: + resolution: {integrity: sha512-Q/fgsgl/dlOAW9ILu4OOhYWQbc7TQd4BwKH/RwmUjyVf8682Be4zj3rOYdLnYEcGzyg8LL9Q5IWYKD8tdToreQ==} prosemirror-schema-basic@1.2.3: resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} @@ -6925,8 +6942,8 @@ packages: prosemirror-state@1.4.3: resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} - prosemirror-tables@1.5.0: - resolution: {integrity: sha512-VMx4zlYWm7aBlZ5xtfJHpqa3Xgu3b7srV54fXYnXgsAcIGRqKSrhiK3f89omzzgaAgAtDOV4ImXnLKhVfheVNQ==} + prosemirror-tables@1.6.1: + resolution: {integrity: sha512-p8WRJNA96jaNQjhJolmbxTzd6M4huRE5xQ8OxjvMhQUP0Nzpo4zz6TztEiwk6aoqGBhz9lxRWR1yRZLlpQN98w==} prosemirror-trailing-node@3.0.0: resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} @@ -6935,11 +6952,11 @@ packages: prosemirror-state: ^1.4.2 prosemirror-view: ^1.33.8 - prosemirror-transform@1.10.0: - resolution: {integrity: sha512-9UOgFSgN6Gj2ekQH5CTDJ8Rp/fnKR2IkYfGdzzp5zQMFsS4zDllLVx/+jGcX86YlACpG7UR5fwAXiWzxqWtBTg==} + prosemirror-transform@1.10.2: + resolution: {integrity: sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==} - prosemirror-view@1.34.3: - resolution: {integrity: sha512-mKZ54PrX19sSaQye+sef+YjBbNu2voNwLS1ivb6aD2IRmxRGW64HU9B644+7OfJStGLyxvOreKqEgfvXa91WIA==} + prosemirror-view@1.36.0: + resolution: {integrity: sha512-U0GQd5yFvV5qUtT41X1zCQfbw14vkbbKwLlQXhdylEmgpYVHkefXYcC4HHwWOfZa3x6Y8wxDLUBv7dxN5XQ3nA==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -6955,9 +6972,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - pump@3.0.2: resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} @@ -7736,8 +7750,8 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} - testcontainers@10.14.0: - resolution: {integrity: sha512-8fReFeQ4bk17T2vHHzcFavBG8UHuHwsdVj+48TchtsCSklwmSUTkg/b57hVjxZdxN1ed/GfF63WZ39I4syV5tQ==} + testcontainers@10.15.0: + resolution: {integrity: sha512-fQbWIdXverYhOVS7WJk3egII1b4OtUl3C9mXIJk7Q95o5HeY/PRbAif5Gxi8tzck7Lmer0rMbq2jSbSbMyYm8Q==} text-decoder@1.2.0: resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} @@ -7745,9 +7759,6 @@ packages: text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} @@ -7791,11 +7802,11 @@ packages: title-case@2.1.1: resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} - tldts-core@6.1.61: - resolution: {integrity: sha512-In7VffkDWUPgwa+c9picLUxvb0RltVwTkSgMNFgvlGSWveCzGBemBqTsgJCL4EDFWZ6WH0fKTsot6yNhzy3ZzQ==} + tldts-core@6.1.63: + resolution: {integrity: sha512-H1XCt54xY+QPbwhTgmxLkepX0MVHu3USfMmejiCOdkMbRcP22Pn2FVF127r/GWXVDmXTRezyF3Ckvhn4Fs6j7Q==} - tldts@6.1.61: - resolution: {integrity: sha512-rv8LUyez4Ygkopqn+M6OLItAOT9FF3REpPQDkdMx5ix8w4qkuE7Vo2o/vw1nxKQYmJDV8JpAMJQr1b+lTKf0FA==} + tldts@6.1.63: + resolution: {integrity: sha512-YWwhsjyn9sB/1rOkSRYxvkN/wl5LFM1QDv6F2pVR+pb/jFne4EOBxHfkKVWvDIBEAw9iGOwwubHtQTm0WRT5sQ==} hasBin: true tmp@0.0.33: @@ -7829,10 +7840,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.4: - resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} - engines: {node: '>=6'} - tough-cookie@5.0.0: resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==} engines: {node: '>=16'} @@ -7925,38 +7932,38 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo-darwin-64@2.3.0: - resolution: {integrity: sha512-pji+D49PhFItyQjf2QVoLZw2d3oRGo8gJgKyOiRzvip78Rzie74quA8XNwSg/DuzM7xx6gJ3p2/LylTTlgZXxQ==} + turbo-darwin-64@2.3.1: + resolution: {integrity: sha512-tjHfjW/Gs8Q9IO+9gPdIsSStZ8I09QYDRT/SyhFTPLnc7O2ZlxHPBVFfjUkHUjanHNYO8CpRGt+zdp1PaMCruw==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.3.0: - resolution: {integrity: sha512-AJrGIL9BO41mwDF/IBHsNGwvtdyB911vp8f5mbNo1wG66gWTvOBg7WCtYQBvCo11XTenTfXPRSsAb7w3WAZb6w==} + turbo-darwin-arm64@2.3.1: + resolution: {integrity: sha512-At1WStnxCfrBQ4M2g6ynre8WsusGwA11okhVolBxyFUemYozDTtbZwelr+IqNggjT251vviokxOkcFzzogbiFw==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.3.0: - resolution: {integrity: sha512-jZqW6vc2sPJT3M/3ZmV1Cg4ecQVPqsbHncG/RnogHpBu783KCSXIndgxvUQNm9qfgBYbZDBnP1md63O4UTElhw==} + turbo-linux-64@2.3.1: + resolution: {integrity: sha512-COwEev7s9fsxLM2eoRCyRLPj+BXvZjFIS+GxzdAubYhoSoZit8B8QGKczyDl6448xhuFEWKrpHhcR9aBuwB4ag==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.3.0: - resolution: {integrity: sha512-HUbDLJlvd/hxuyCNO0BmEWYQj0TugRMvSQeG8vHJH+Lq8qOgDAe7J0K73bFNbZejZQxW3C3XEiZFB3pnpO78+A==} + turbo-linux-arm64@2.3.1: + resolution: {integrity: sha512-AP0uE15Rhxza2Jl+Q3gxdXRA92IIeFAYaufz6CMcZuGy9yZsBlLt9w6T47H6g7XQPzWuw8pzfjM1omcTKkkDpQ==} cpu: [arm64] os: [linux] - turbo-windows-64@2.3.0: - resolution: {integrity: sha512-c5rxrGNTYDWX9QeMzWLFE9frOXnKjHGEvQMp1SfldDlbZYsloX9UKs31TzUThzfTgTiz8NYuShaXJ2UvTMnV/g==} + turbo-windows-64@2.3.1: + resolution: {integrity: sha512-HDSneq0dNZYZch74c2eygq+OiJE/JYDs7OsGM0yRYVj336383xkUnxz6W2I7qiyMCQXzp4UVUDZXvZhUYcX3BA==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.3.0: - resolution: {integrity: sha512-7qfUuYhfIVb1AZgs89DxhXK+zZez6O2ocmixEQ4hXZK7ytnBt5vaz2zGNJJKFNYIL5HX1C3tuHolnpNgDNCUIg==} + turbo-windows-arm64@2.3.1: + resolution: {integrity: sha512-7/2/sJZiquwoT/jWBCfV0qKq4NarsJPmDRjMcR9dDMIwCYsGM8ljomkDRTCtkNeFcUvYw54MiRWHehWgbcRPsw==} cpu: [arm64] os: [win32] - turbo@2.3.0: - resolution: {integrity: sha512-/uOq5o2jwRPyaUDnwBpOR5k9mQq4c3wziBgWNWttiYQPmbhDtrKYPRBxTvA2WpgQwRIbt8UM612RMN8n/TvmHA==} + turbo@2.3.1: + resolution: {integrity: sha512-vHZe/e6k1HZVKiMQPQ1BWFn53vjVQDFKdkjUq/pBKlRWi1gw9LQO6ntH4qZCcHY1rH6TXgsRmexXdgWl96YvVQ==} hasBin: true tweetnacl@0.14.5: @@ -8004,10 +8011,11 @@ packages: types-ramda@0.30.1: resolution: {integrity: sha512-1HTsf5/QVRmLzcGfldPFvkVsAdi1db1BBKzi7iW3KBUlOICg/nKnFS+jGqDJS3YD8VsWbAh7JiHeBvbsw8RPxA==} - typescript-eslint@8.14.0: - resolution: {integrity: sha512-K8fBJHxVL3kxMmwByvz8hNdBJ8a0YqKzKDX6jRlrjMuNXyd5T2V02HIq37+OiWXvUUOXgOOGiSSOh26Mh8pC3w==} + typescript-eslint@8.15.0: + resolution: {integrity: sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: @@ -8054,10 +8062,6 @@ packages: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -8221,8 +8225,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-tsconfig-paths@5.1.2: - resolution: {integrity: sha512-gEIbKfJzSEv0yR3XS2QEocKetONoWkbROj6hGx0FHM18qKUojhvcokQsxQx5nMkelZq2n37zbSGCJn+FSODSjA==} + vite-tsconfig-paths@5.1.3: + resolution: {integrity: sha512-0bz+PDlLpGfP2CigeSKL9NFTF1KtXkeHGZSSaGQSuPZH77GhoiQaA8IjYgOaynSuwlDTolSUEU0ErVvju3NURg==} peerDependencies: vite: '*' peerDependenciesMeta: @@ -8543,18 +8547,17 @@ snapshots: preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) - '@auth/core@0.37.3': + '@auth/core@0.37.4': dependencies: '@panva/hkdf': 1.2.1 - cookie: 1.0.1 jose: 5.9.6 oauth4webapi: 3.1.2 preact: 10.24.3 preact-render-to-string: 6.5.11(preact@10.24.3) - '@auth/drizzle-adapter@1.7.3': + '@auth/drizzle-adapter@1.7.4': dependencies: - '@auth/core': 0.37.3 + '@auth/core': 0.37.4 transitivePeerDependencies: - '@simplewebauthn/browser' - '@simplewebauthn/server' @@ -8815,13 +8818,13 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@ctrl/deluge@6.1.0': + '@ctrl/deluge@7.0.0': dependencies: '@ctrl/magnet-link': 4.0.2 - '@ctrl/shared-torrent': 6.0.0 + '@ctrl/shared-torrent': 6.1.0 node-fetch-native: 1.6.4 - ofetch: 1.3.4 - tough-cookie: 4.1.4 + ofetch: 1.4.1 + tough-cookie: 5.0.0 ufo: 1.5.4 uint8array-extras: 1.4.0 @@ -8830,19 +8833,17 @@ snapshots: rfc4648: 1.5.3 uint8array-extras: 1.4.0 - '@ctrl/qbittorrent@9.0.1': + '@ctrl/qbittorrent@9.1.0': dependencies: '@ctrl/magnet-link': 4.0.2 - '@ctrl/shared-torrent': 6.0.0 + '@ctrl/shared-torrent': 6.1.0 '@ctrl/torrent-file': 4.1.0 - cookie: 0.6.0 + cookie: 1.0.1 node-fetch-native: 1.6.4 - ofetch: 1.3.4 + ofetch: 1.4.1 ufo: 1.5.4 uint8array-extras: 1.4.0 - '@ctrl/shared-torrent@6.0.0': {} - '@ctrl/shared-torrent@6.1.0': {} '@ctrl/torrent-file@4.1.0': @@ -9247,14 +9248,14 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.14.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.15.0)': dependencies: - eslint: 9.14.0 + eslint: 9.15.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.18.0': + '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.7 @@ -9262,9 +9263,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/core@0.7.0': {} + '@eslint/core@0.9.0': {} - '@eslint/eslintrc@3.1.0': + '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 debug: 4.3.7 @@ -9278,11 +9279,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.14.0': {} + '@eslint/js@9.15.0': {} '@eslint/object-schema@2.1.4': {} - '@eslint/plugin-kit@0.2.0': + '@eslint/plugin-kit@0.2.3': dependencies: levn: 0.4.1 @@ -9386,7 +9387,7 @@ snapshots: '@humanwhocodes/retry@0.3.1': {} - '@humanwhocodes/retry@0.4.0': {} + '@humanwhocodes/retry@0.4.1': {} '@ianvs/prettier-plugin-sort-imports@4.4.0(prettier@3.3.3)': dependencies: @@ -9454,14 +9455,14 @@ snapshots: js-base64: 3.7.7 optional: true - '@mantine/colors-generator@7.14.0(chroma-js@3.1.2)': + '@mantine/colors-generator@7.14.1(chroma-js@3.1.2)': dependencies: chroma-js: 3.1.2 - '@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react': 0.26.27(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) clsx: 2.1.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -9472,59 +9473,59 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) clsx: 2.1.1 dayjs: 1.11.13 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@mantine/form@7.14.0(react@18.3.1)': + '@mantine/form@7.14.1(react@18.3.1)': dependencies: fast-deep-equal: 3.1.3 klona: 2.0.6 react: 18.3.1 - '@mantine/hooks@7.14.0(react@18.3.1)': + '@mantine/hooks@7.14.1(react@18.3.1)': dependencies: react: 18.3.1 - '@mantine/modals@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/modals@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@mantine/notifications@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/notifications@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) - '@mantine/store': 7.14.0(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) + '@mantine/store': 7.14.1(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/spotlight@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/spotlight@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) - '@mantine/store': 7.14.0(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) + '@mantine/store': 7.14.1(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@mantine/store@7.14.0(react@18.3.1)': + '@mantine/store@7.14.1(react@18.3.1)': dependencies: react: 18.3.1 - '@mantine/tiptap@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tiptap/extension-link@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1))(@tiptap/react@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/tiptap@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tiptap/extension-link@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2))(@tiptap/react@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) - '@tiptap/extension-link': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/react': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) + '@tiptap/extension-link': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/react': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -10153,25 +10154,25 @@ snapshots: dependencies: remove-accents: 0.5.0 - '@tanstack/query-core@5.60.5': {} + '@tanstack/query-core@5.60.6': {} '@tanstack/query-devtools@5.59.20': {} - '@tanstack/react-query-devtools@5.60.5(@tanstack/react-query@5.60.5(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-devtools@5.61.0(@tanstack/react-query@5.61.0(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.59.20 - '@tanstack/react-query': 5.60.5(react@18.3.1) + '@tanstack/react-query': 5.61.0(react@18.3.1) react: 18.3.1 - '@tanstack/react-query-next-experimental@5.60.5(@tanstack/react-query@5.60.5(react@18.3.1))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react@18.3.1)': + '@tanstack/react-query-next-experimental@5.61.0(@tanstack/react-query@5.61.0(react@18.3.1))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react@18.3.1)': dependencies: - '@tanstack/react-query': 5.60.5(react@18.3.1) + '@tanstack/react-query': 5.61.0(react@18.3.1) next: 14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) react: 18.3.1 - '@tanstack/react-query@5.60.5(react@18.3.1)': + '@tanstack/react-query@5.61.0(react@18.3.1)': dependencies: - '@tanstack/query-core': 5.60.5 + '@tanstack/query-core': 5.60.6 react: 18.3.1 '@tanstack/react-table@8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -10190,218 +10191,218 @@ snapshots: '@tanstack/virtual-core@3.10.8': {} - '@testcontainers/mysql@10.14.0': + '@testcontainers/mysql@10.15.0': dependencies: - testcontainers: 10.14.0 + testcontainers: 10.15.0 transitivePeerDependencies: - supports-color - '@tiptap/core@2.9.1(@tiptap/pm@2.9.1)': + '@tiptap/core@2.10.2(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/pm': 2.9.1 + '@tiptap/pm': 2.10.2 - '@tiptap/extension-blockquote@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-blockquote@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-bold@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-bold@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-bubble-menu@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-bubble-menu@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 tippy.js: 6.3.7 - '@tiptap/extension-bullet-list@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-bullet-list@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-code-block@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-code-block@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-code@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-code@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-color@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/extension-text-style@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)))': + '@tiptap/extension-color@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/extension-text-style@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/extension-text-style': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/extension-text-style': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) - '@tiptap/extension-document@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-document@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-dropcursor@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-dropcursor@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-floating-menu@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-floating-menu@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 tippy.js: 6.3.7 - '@tiptap/extension-gapcursor@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-gapcursor@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-hard-break@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-hard-break@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-heading@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-heading@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-highlight@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-highlight@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-history@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-history@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-horizontal-rule@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-horizontal-rule@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-image@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-image@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-italic@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-italic@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-link@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-link@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 linkifyjs: 4.1.3 - '@tiptap/extension-list-item@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-list-item@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-ordered-list@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-ordered-list@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-paragraph@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-paragraph@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-strike@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-strike@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-table-cell@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-table-cell@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-table-header@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-table-header@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-table-row@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-table-row@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-table@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-table@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-task-item@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)': + '@tiptap/extension-task-item@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 - '@tiptap/extension-task-list@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-task-list@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-text-align@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-text-align@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-text-style@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-text-style@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-text@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-text@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/extension-underline@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))': + '@tiptap/extension-underline@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) - '@tiptap/pm@2.9.1': + '@tiptap/pm@2.10.2': dependencies: prosemirror-changeset: 2.2.1 prosemirror-collab: 1.3.1 - prosemirror-commands: 1.6.0 + prosemirror-commands: 1.6.2 prosemirror-dropcursor: 1.8.1 prosemirror-gapcursor: 1.3.2 prosemirror-history: 1.4.1 prosemirror-inputrules: 1.4.0 prosemirror-keymap: 1.2.2 - prosemirror-markdown: 1.13.0 + prosemirror-markdown: 1.13.1 prosemirror-menu: 1.2.4 - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-schema-basic: 1.2.3 prosemirror-schema-list: 1.4.1 prosemirror-state: 1.4.3 - prosemirror-tables: 1.5.0 - prosemirror-trailing-node: 3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3) - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-tables: 1.6.1 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.23.0)(prosemirror-state@1.4.3)(prosemirror-view@1.36.0) + prosemirror-transform: 1.10.2 + prosemirror-view: 1.36.0 - '@tiptap/react@2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tiptap/react@2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/extension-bubble-menu': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-floating-menu': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/extension-bubble-menu': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-floating-menu': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/pm': 2.10.2 '@types/use-sync-external-store': 0.0.6 fast-deep-equal: 3.1.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.2.2(react@18.3.1) - '@tiptap/starter-kit@2.9.1': + '@tiptap/starter-kit@2.10.2': dependencies: - '@tiptap/core': 2.9.1(@tiptap/pm@2.9.1) - '@tiptap/extension-blockquote': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-bold': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-bullet-list': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-code': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-code-block': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-document': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-dropcursor': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-gapcursor': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-hard-break': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-heading': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-history': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-horizontal-rule': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1))(@tiptap/pm@2.9.1) - '@tiptap/extension-italic': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-list-item': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-ordered-list': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-paragraph': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-strike': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-text': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/extension-text-style': 2.9.1(@tiptap/core@2.9.1(@tiptap/pm@2.9.1)) - '@tiptap/pm': 2.9.1 + '@tiptap/core': 2.10.2(@tiptap/pm@2.10.2) + '@tiptap/extension-blockquote': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-bold': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-bullet-list': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-code': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-code-block': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-document': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-dropcursor': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-gapcursor': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-hard-break': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-heading': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-history': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-horizontal-rule': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2))(@tiptap/pm@2.10.2) + '@tiptap/extension-italic': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-list-item': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-ordered-list': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-paragraph': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-strike': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-text': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/extension-text-style': 2.10.2(@tiptap/core@2.10.2(@tiptap/pm@2.10.2)) + '@tiptap/pm': 2.10.2 '@tootallnate/quickjs-emscripten@0.23.0': {} @@ -10413,7 +10414,7 @@ snapshots: dependencies: '@trpc/server': 11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) - '@trpc/next@11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@trpc/next@11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@trpc/client': 11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)) '@trpc/server': 11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) @@ -10421,20 +10422,20 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@tanstack/react-query': 5.60.5(react@18.3.1) - '@trpc/react-query': 11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-query': 5.61.0(react@18.3.1) + '@trpc/react-query': 11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/react-query': 5.60.5(react@18.3.1) + '@tanstack/react-query': 5.61.0(react@18.3.1) '@trpc/client': 11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)) '@trpc/server': 11.0.0-rc.638(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.60.5(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@trpc/react-query@11.0.0-rc.638(@tanstack/react-query@5.61.0(react@18.3.1))(@trpc/client@11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)))(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/react-query': 5.60.5(react@18.3.1) + '@tanstack/react-query': 5.61.0(react@18.3.1) '@trpc/client': 11.0.0-rc.638(@trpc/server@11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0)) '@trpc/server': 11.0.0-rc.638(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.81.0) react: 18.3.1 @@ -10488,9 +10489,9 @@ snapshots: '@tsconfig/svelte@1.0.13': {} - '@turbo/gen@2.3.0(@types/node@22.9.0)(typescript@5.6.3)': + '@turbo/gen@2.3.1(@types/node@22.9.1)(typescript@5.6.3)': dependencies: - '@turbo/workspaces': 2.3.0 + '@turbo/workspaces': 2.3.1 commander: 10.0.1 fs-extra: 10.1.0 inquirer: 8.2.6 @@ -10498,7 +10499,7 @@ snapshots: node-plop: 0.26.3 picocolors: 1.0.1 proxy-agent: 6.4.0 - ts-node: 10.9.2(@types/node@22.9.0)(typescript@5.6.3) + ts-node: 10.9.2(@types/node@22.9.1)(typescript@5.6.3) update-check: 1.5.4 validate-npm-package-name: 5.0.1 transitivePeerDependencies: @@ -10508,7 +10509,7 @@ snapshots: - supports-color - typescript - '@turbo/workspaces@2.3.0': + '@turbo/workspaces@2.3.1': dependencies: commander: 10.0.1 execa: 5.1.1 @@ -10525,7 +10526,7 @@ snapshots: '@types/asn1@0.2.4': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/aws-lambda@8.10.145': optional: true @@ -10553,22 +10554,22 @@ snapshots: '@types/bcrypt@5.0.2': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 - '@types/better-sqlite3@7.6.11': + '@types/better-sqlite3@7.6.12': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/chroma-js@2.4.4': {} '@types/connect@3.4.38': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/cookie@0.6.0': {} @@ -10577,7 +10578,7 @@ snapshots: '@types/connect': 3.4.38 '@types/express': 4.17.21 '@types/keygrip': 1.0.6 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/css-font-loading-module@0.0.7': {} @@ -10585,13 +10586,13 @@ snapshots: '@types/docker-modem@3.0.6': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/ssh2': 1.15.1 - '@types/dockerode@3.3.31': + '@types/dockerode@3.3.32': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/ssh2': 1.15.1 '@types/estree@1.0.5': {} @@ -10600,7 +10601,7 @@ snapshots: '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/qs': 6.9.16 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -10615,7 +10616,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/hast@2.3.10': dependencies: @@ -10634,6 +10635,15 @@ snapshots: '@types/keygrip@1.0.6': {} + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} @@ -10644,7 +10654,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@22.9.0': + '@types/node@22.9.1': dependencies: undici-types: 6.19.8 @@ -10672,21 +10682,21 @@ snapshots: '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/send': 0.17.4 '@types/ssh2-streams@0.1.12': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/ssh2@0.5.52': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/ssh2-streams': 0.1.12 '@types/ssh2@1.15.1': @@ -10699,7 +10709,7 @@ snapshots: '@types/through@0.0.33': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/tinycolor2@1.4.6': {} @@ -10715,21 +10725,21 @@ snapshots: '@types/ws@8.5.13': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@types/xml2js@0.4.14': dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 - '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.15.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/type-utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.14.0 - eslint: 9.14.0 + '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.15.0 + '@typescript-eslint/type-utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.15.0 + eslint: 9.15.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -10739,42 +10749,42 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/scope-manager': 8.15.0 + '@typescript-eslint/types': 8.15.0 + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.15.0 debug: 4.3.7 - eslint: 9.14.0 + eslint: 9.15.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.14.0': + '@typescript-eslint/scope-manager@8.15.0': dependencies: - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/types': 8.15.0 + '@typescript-eslint/visitor-keys': 8.15.0 - '@typescript-eslint/type-utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.15.0(eslint@9.15.0)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) debug: 4.3.7 + eslint: 9.15.0 ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - - eslint - supports-color - '@typescript-eslint/types@8.14.0': {} + '@typescript-eslint/types@8.15.0': {} - '@typescript-eslint/typescript-estree@8.14.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.15.0(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/visitor-keys': 8.14.0 + '@typescript-eslint/types': 8.15.0 + '@typescript-eslint/visitor-keys': 8.15.0 debug: 4.3.7 fast-glob: 3.3.2 is-glob: 4.0.3 @@ -10786,21 +10796,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': + '@typescript-eslint/utils@8.15.0(eslint@9.15.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.14.0) - '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/types': 8.14.0 - '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - eslint: 9.14.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.15.0) + '@typescript-eslint/scope-manager': 8.15.0 + '@typescript-eslint/types': 8.15.0 + '@typescript-eslint/typescript-estree': 8.15.0(typescript@5.6.3) + eslint: 9.15.0 + optionalDependencies: + typescript: 5.6.3 transitivePeerDependencies: - supports-color - - typescript - '@typescript-eslint/visitor-keys@8.14.0': + '@typescript-eslint/visitor-keys@8.15.0': dependencies: - '@typescript-eslint/types': 8.14.0 - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.15.0 + eslint-visitor-keys: 4.2.0 '@umami/node@0.4.0': {} @@ -10832,14 +10843,14 @@ snapshots: global: 4.4.0 is-function: 1.0.2 - '@vitejs/plugin-react@4.3.3(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': + '@vitejs/plugin-react@4.3.3(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color @@ -10857,7 +10868,7 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.5(@types/node@22.9.0)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vitest: 2.1.5(@types/node@22.9.1)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color @@ -10868,13 +10879,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.5(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': + '@vitest/mocker@2.1.5(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': dependencies: '@vitest/spy': 2.1.5 estree-walker: 3.0.3 magic-string: 0.30.12 optionalDependencies: - vite: 5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) '@vitest/pretty-format@2.1.5': dependencies: @@ -10904,7 +10915,7 @@ snapshots: sirv: 3.0.0 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.5(@types/node@22.9.0)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vitest: 2.1.5(@types/node@22.9.1)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) '@vitest/utils@2.1.5': dependencies: @@ -11657,8 +11668,6 @@ snapshots: cookie-signature@1.0.6: optional: true - cookie@0.6.0: {} - cookie@0.7.1: {} cookie@0.7.2: {} @@ -11715,6 +11724,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cross-spawn@7.0.5: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + crypto-random-string@2.0.0: {} css.escape@1.5.1: {} @@ -11907,9 +11928,9 @@ snapshots: dependencies: is-obj: 2.0.0 - dotenv-cli@7.4.2: + dotenv-cli@7.4.4: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 dotenv: 16.4.5 dotenv-expand: 10.0.0 minimist: 1.2.8 @@ -11931,10 +11952,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.36.3(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.11)(@types/react@18.3.12)(better-sqlite3@11.5.0)(mysql2@3.11.4)(react@18.3.1): + drizzle-orm@0.36.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@18.3.12)(better-sqlite3@11.5.0)(mysql2@3.11.4)(react@18.3.1): optionalDependencies: '@libsql/client-wasm': 0.14.0 - '@types/better-sqlite3': 7.6.11 + '@types/better-sqlite3': 7.6.12 '@types/react': 18.3.12 better-sqlite3: 11.5.0 mysql2: 3.11.4 @@ -12240,14 +12261,14 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@9.1.0(eslint@9.14.0): + eslint-config-prettier@9.1.0(eslint@9.15.0): dependencies: - eslint: 9.14.0 + eslint: 9.15.0 - eslint-config-turbo@2.3.0(eslint@9.14.0): + eslint-config-turbo@2.3.1(eslint@9.15.0): dependencies: - eslint: 9.14.0 - eslint-plugin-turbo: 2.3.0(eslint@9.14.0) + eslint: 9.15.0 + eslint-plugin-turbo: 2.3.1(eslint@9.15.0) eslint-import-resolver-node@0.3.9: dependencies: @@ -12257,17 +12278,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.14.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.15.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - eslint: 9.14.0 + '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + eslint: 9.15.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -12276,9 +12297,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.14.0 + eslint: 9.15.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.14.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.15.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -12290,13 +12311,13 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.14.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.15.0): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -12306,7 +12327,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.14.0 + eslint: 9.15.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -12315,11 +12336,11 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.0.0(eslint@9.14.0): + eslint-plugin-react-hooks@5.0.0(eslint@9.15.0): dependencies: - eslint: 9.14.0 + eslint: 9.15.0 - eslint-plugin-react@7.37.2(eslint@9.14.0): + eslint-plugin-react@7.37.2(eslint@9.15.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -12327,7 +12348,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.1.0 - eslint: 9.14.0 + eslint: 9.15.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -12341,10 +12362,10 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.3.0(eslint@9.14.0): + eslint-plugin-turbo@2.3.1(eslint@9.15.0): dependencies: dotenv: 16.0.3 - eslint: 9.14.0 + eslint: 9.15.0 eslint-scope@5.1.1: dependencies: @@ -12360,23 +12381,23 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.14.0: + eslint@9.15.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.14.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.15.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.18.0 - '@eslint/core': 0.7.0 - '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.14.0 - '@eslint/plugin-kit': 0.2.0 + '@eslint/config-array': 0.19.0 + '@eslint/core': 0.9.0 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.15.0 + '@eslint/plugin-kit': 0.2.3 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.0 + '@humanwhocodes/retry': 0.4.1 '@types/estree': 1.0.6 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 @@ -12396,7 +12417,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - text-table: 0.2.0 transitivePeerDependencies: - supports-color @@ -12437,7 +12457,7 @@ snapshots: execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.5 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -13265,7 +13285,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -13273,7 +13293,7 @@ snapshots: jose@5.9.6: {} - jotai@2.10.2(@types/react@18.3.12)(react@18.3.1): + jotai@2.10.3(@types/react@18.3.12)(react@18.3.1): optionalDependencies: '@types/react': 18.3.12 react: 18.3.1 @@ -13510,11 +13530,11 @@ snapshots: make-error@1.3.6: {} - mantine-react-table@2.0.0-beta.7(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + mantine-react-table@2.0.0-beta.7(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/dates@7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(@tabler/icons-react@3.22.0(react@18.3.1))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@mantine/core': 7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/dates': 7.14.0(@mantine/core@7.14.0(@mantine/hooks@7.14.0(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.0(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 7.14.0(react@18.3.1) + '@mantine/core': 7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/dates': 7.14.1(@mantine/core@7.14.1(@mantine/hooks@7.14.1(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@7.14.1(react@18.3.1))(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 7.14.1(react@18.3.1) '@tabler/icons-react': 3.22.0(react@18.3.1) '@tanstack/match-sorter-utils': 8.19.4 '@tanstack/react-table': 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -13791,7 +13811,7 @@ snapshots: node-mocks-http@1.16.0: dependencies: '@types/express': 4.17.21 - '@types/node': 22.9.0 + '@types/node': 22.9.1 accepts: 1.3.8 content-disposition: 0.5.4 depd: 1.1.2 @@ -13880,12 +13900,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - ofetch@1.3.4: - dependencies: - destr: 2.0.3 - node-fetch-native: 1.6.4 - ufo: 1.5.4 - ofetch@1.4.1: dependencies: destr: 2.0.3 @@ -14212,105 +14226,106 @@ snapshots: prosemirror-changeset@2.2.1: dependencies: - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.10.2 prosemirror-collab@1.3.1: dependencies: prosemirror-state: 1.4.3 - prosemirror-commands@1.6.0: + prosemirror-commands@1.6.2: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.10.2 prosemirror-dropcursor@1.8.1: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.36.0 prosemirror-gapcursor@1.3.2: dependencies: prosemirror-keymap: 1.2.2 - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-view: 1.34.3 + prosemirror-view: 1.36.0 prosemirror-history@1.4.1: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.36.0 rope-sequence: 1.3.4 prosemirror-inputrules@1.4.0: dependencies: prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.10.2 prosemirror-keymap@1.2.2: dependencies: prosemirror-state: 1.4.3 w3c-keyname: 2.2.8 - prosemirror-markdown@1.13.0: + prosemirror-markdown@1.13.1: dependencies: + '@types/markdown-it': 14.1.2 markdown-it: 14.1.0 - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-menu@1.2.4: dependencies: crelt: 1.0.6 - prosemirror-commands: 1.6.0 + prosemirror-commands: 1.6.2 prosemirror-history: 1.4.1 prosemirror-state: 1.4.3 - prosemirror-model@1.22.3: + prosemirror-model@1.23.0: dependencies: orderedmap: 2.1.1 prosemirror-schema-basic@1.2.3: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-schema-list@1.4.1: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.10.2 prosemirror-state@1.4.3: dependencies: - prosemirror-model: 1.22.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-model: 1.23.0 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.36.0 - prosemirror-tables@1.5.0: + prosemirror-tables@1.6.1: dependencies: prosemirror-keymap: 1.2.2 - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 - prosemirror-view: 1.34.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.36.0 - prosemirror-trailing-node@3.0.0(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.34.3): + prosemirror-trailing-node@3.0.0(prosemirror-model@1.23.0)(prosemirror-state@1.4.3)(prosemirror-view@1.36.0): dependencies: '@remirror/core-constants': 3.0.0 escape-string-regexp: 4.0.0 - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-view: 1.34.3 + prosemirror-view: 1.36.0 - prosemirror-transform@1.10.0: + prosemirror-transform@1.10.2: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 - prosemirror-view@1.34.3: + prosemirror-view@1.36.0: dependencies: - prosemirror-model: 1.22.3 + prosemirror-model: 1.23.0 prosemirror-state: 1.4.3 - prosemirror-transform: 1.10.0 + prosemirror-transform: 1.10.2 proto-list@1.2.4: {} @@ -14335,8 +14350,6 @@ snapshots: proxy-from-env@1.1.0: {} - psl@1.9.0: {} - pump@3.0.2: dependencies: end-of-stream: 1.4.4 @@ -15275,10 +15288,10 @@ snapshots: glob: 10.4.5 minimatch: 9.0.5 - testcontainers@10.14.0: + testcontainers@10.15.0: dependencies: '@balena/dockerignore': 1.0.2 - '@types/dockerode': 3.3.31 + '@types/dockerode': 3.3.32 archiver: 7.0.1 async-lock: 1.4.1 byline: 5.0.0 @@ -15301,8 +15314,6 @@ snapshots: text-hex@1.0.0: {} - text-table@0.2.0: {} - thread-stream@3.1.0: dependencies: real-require: 0.2.0 @@ -15343,11 +15354,11 @@ snapshots: no-case: 2.3.2 upper-case: 1.1.3 - tldts-core@6.1.61: {} + tldts-core@6.1.63: {} - tldts@6.1.61: + tldts@6.1.63: dependencies: - tldts-core: 6.1.61 + tldts-core: 6.1.63 tmp@0.0.33: dependencies: @@ -15370,16 +15381,9 @@ snapshots: totalist@3.0.1: {} - tough-cookie@4.1.4: - dependencies: - psl: 1.9.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tough-cookie@5.0.0: dependencies: - tldts: 6.1.61 + tldts: 6.1.63 tr46@0.0.3: {} @@ -15425,14 +15429,14 @@ snapshots: ts-mixer@6.0.4: {} - ts-node@10.9.2(@types/node@22.9.0)(typescript@5.6.3): + ts-node@10.9.2(@types/node@22.9.1)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.9.0 + '@types/node': 22.9.1 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -15473,32 +15477,32 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo-darwin-64@2.3.0: + turbo-darwin-64@2.3.1: optional: true - turbo-darwin-arm64@2.3.0: + turbo-darwin-arm64@2.3.1: optional: true - turbo-linux-64@2.3.0: + turbo-linux-64@2.3.1: optional: true - turbo-linux-arm64@2.3.0: + turbo-linux-arm64@2.3.1: optional: true - turbo-windows-64@2.3.0: + turbo-windows-64@2.3.1: optional: true - turbo-windows-arm64@2.3.0: + turbo-windows-arm64@2.3.1: optional: true - turbo@2.3.0: + turbo@2.3.1: optionalDependencies: - turbo-darwin-64: 2.3.0 - turbo-darwin-arm64: 2.3.0 - turbo-linux-64: 2.3.0 - turbo-linux-arm64: 2.3.0 - turbo-windows-64: 2.3.0 - turbo-windows-arm64: 2.3.0 + turbo-darwin-64: 2.3.1 + turbo-darwin-arm64: 2.3.1 + turbo-linux-64: 2.3.1 + turbo-linux-arm64: 2.3.1 + turbo-windows-64: 2.3.1 + turbo-windows-arm64: 2.3.1 tweetnacl@0.14.5: {} @@ -15557,15 +15561,15 @@ snapshots: dependencies: ts-toolbelt: 9.6.0 - typescript-eslint@8.14.0(eslint@9.14.0)(typescript@5.6.3): + typescript-eslint@8.15.0(eslint@9.15.0)(typescript@5.6.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 8.15.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.6.3))(eslint@9.15.0)(typescript@5.6.3) + '@typescript-eslint/parser': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.15.0(eslint@9.15.0)(typescript@5.6.3) + eslint: 9.15.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - - eslint - supports-color typescript@5.6.3: {} @@ -15600,8 +15604,6 @@ snapshots: dependencies: crypto-random-string: 2.0.0 - universalify@0.2.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -15762,13 +15764,13 @@ snapshots: dependencies: global: 4.4.0 - vite-node@2.1.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vite-node@2.1.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: cac: 6.7.14 debug: 4.3.7 es-module-lexer: 1.5.4 pathe: 1.1.2 - vite: 5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - '@types/node' - less @@ -15780,33 +15782,33 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@5.1.2(typescript@5.6.3)(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)): + vite-tsconfig-paths@5.1.3(typescript@5.6.3)(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)): dependencies: debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.1.3(typescript@5.6.3) optionalDependencies: - vite: 5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color - typescript - vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.21.3 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 fsevents: 2.3.3 sass: 1.81.0 sugarss: 4.0.1(postcss@8.4.47) terser: 5.32.0 - vitest@2.1.5(@types/node@22.9.0)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vitest@2.1.5(@types/node@22.9.1)(@vitest/ui@2.1.5)(jsdom@25.0.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: '@vitest/expect': 2.1.5 - '@vitest/mocker': 2.1.5(vite@5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + '@vitest/mocker': 2.1.5(vite@5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) '@vitest/pretty-format': 2.1.5 '@vitest/runner': 2.1.5 '@vitest/snapshot': 2.1.5 @@ -15822,11 +15824,11 @@ snapshots: tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) - vite-node: 2.1.5(@types/node@22.9.0)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite-node: 2.1.5(@types/node@22.9.1)(sass@1.81.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.9.0 + '@types/node': 22.9.1 '@vitest/ui': 2.1.5(vitest@2.1.5) jsdom: 25.0.1 transitivePeerDependencies: diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json index f82b0b8f1..ce54975b8 100644 --- a/tooling/eslint/package.json +++ b/tooling/eslint/package.json @@ -18,17 +18,17 @@ "dependencies": { "@next/eslint-plugin-next": "^14.2.18", "eslint-config-prettier": "^9.1.0", - "eslint-config-turbo": "^2.3.0", + "eslint-config-turbo": "^2.3.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", - "typescript-eslint": "^8.14.0" + "typescript-eslint": "^8.15.0" }, "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config"