From 29c384f0bb5a4223b7e62df986806d532b3dc274 Mon Sep 17 00:00:00 2001 From: Chairil Fauzi Firmansyah Date: Thu, 4 Sep 2025 16:23:41 +0700 Subject: [PATCH 001/412] fix(tracker): prevent multiple initialization when script injected more than once --- src/tracker/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tracker/index.js b/src/tracker/index.js index 76d29a1dd..412d5e13b 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -1,4 +1,7 @@ (window => { + if (window.__umami_tracker_loaded) return; + window.__umami_tracker_loaded = true; + const { screen: { width, height }, navigator: { language, doNotTrack: ndnt, msDoNotTrack: msdnt }, From e85ef4a9c53a665b944dcfd5886b6e6064a23594 Mon Sep 17 00:00:00 2001 From: Antti Hilja Date: Sat, 4 Oct 2025 17:33:15 +0200 Subject: [PATCH 002/412] =?UTF-8?q?Set=20tracker=E2=80=99s=20fetch=20call?= =?UTF-8?q?=20priority=20to=20low?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Analytic is important activity but not as important as main business logic. Setting low priority doesn't mean the fetch call will be more likely to be discarded etc. it's just a hint to the browser. --- src/tracker/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tracker/index.js b/src/tracker/index.js index b05d90859..319ed8d97 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -166,6 +166,7 @@ ...(typeof cache !== 'undefined' && { 'x-umami-cache': cache }), }, credentials: 'omit', + priority: 'low', }); const data = await res.json(); From 7edddf15a7cfe27b63b002d46581a7766b758dd3 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 28 Nov 2025 00:37:51 -0800 Subject: [PATCH 003/412] Boards schema. --- pnpm-lock.yaml | 48 +++++++++++++++++++++++ prisma/migrations/15_boards/migration.sql | 33 ++++++++++++++++ prisma/schema.prisma | 24 ++++++++++++ src/app/(main)/SideNav.tsx | 8 +++- 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/15_boards/migration.sql diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a4577c16..16b8ab668 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -328,6 +328,45 @@ importers: specifier: ^5.9.3 version: 5.9.3 + dist: + dependencies: + chart.js: + specifier: ^4.5.0 + version: 4.5.1 + chartjs-adapter-date-fns: + specifier: ^3.0.0 + version: 3.0.0(chart.js@4.5.1)(date-fns@2.30.0) + colord: + specifier: ^2.9.2 + version: 2.9.3 + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 + lucide-react: + specifier: ^0.542.0 + version: 0.542.0(react@19.2.0) + pure-rand: + specifier: ^7.0.1 + version: 7.0.1 + react-simple-maps: + specifier: ^2.3.0 + version: 2.3.0(prop-types@15.8.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-use-measure: + specifier: ^2.0.4 + version: 2.1.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-window: + specifier: ^1.8.6 + version: 1.8.11(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + serialize-error: + specifier: ^12.0.0 + version: 12.0.0 + thenby: + specifier: ^1.3.4 + version: 1.3.4 + uuid: + specifier: ^11.1.0 + version: 11.1.0 + packages: '@ampproject/remapping@2.3.0': @@ -5047,6 +5086,11 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lucide-react@0.542.0: + resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lucide-react@0.543.0: resolution: {integrity: sha512-fpVfuOQO0V3HBaOA1stIiP/A2fPCXHIleRZL16Mx3HmjTYwNSbimhnFBygs2CAfU1geexMX5ItUcWBGUaqw5CA==} peerDependencies: @@ -12656,6 +12700,10 @@ snapshots: dependencies: react: 19.2.0 + lucide-react@0.542.0(react@19.2.0): + dependencies: + react: 19.2.0 + lucide-react@0.543.0(react@19.2.0): dependencies: react: 19.2.0 diff --git a/prisma/migrations/15_boards/migration.sql b/prisma/migrations/15_boards/migration.sql new file mode 100644 index 000000000..09608c5fd --- /dev/null +++ b/prisma/migrations/15_boards/migration.sql @@ -0,0 +1,33 @@ +-- CreateTable +CREATE TABLE "board" ( + "board_id" UUID NOT NULL, + "type" VARCHAR(50) NOT NULL, + "name" VARCHAR(200) NOT NULL, + "description" VARCHAR(500) NOT NULL, + "parameters" JSONB NOT NULL, + "slug" VARCHAR(100) NOT NULL, + "user_id" UUID, + "team_id" UUID, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6), + + CONSTRAINT "board_pkey" PRIMARY KEY ("board_id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "board_board_id_key" ON "board"("board_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "board_slug_key" ON "board"("slug"); + +-- CreateIndex +CREATE INDEX "board_slug_idx" ON "board"("slug"); + +-- CreateIndex +CREATE INDEX "board_user_id_idx" ON "board"("user_id"); + +-- CreateIndex +CREATE INDEX "board_team_id_idx" ON "board"("team_id"); + +-- CreateIndex +CREATE INDEX "board_created_at_idx" ON "board"("created_at"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aeb11648d..c0c03784d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,6 +27,7 @@ model User { pixels Pixel[] @relation("user") teams TeamUser[] reports Report[] + boards Board[] @relation("user") @@map("user") } @@ -199,6 +200,7 @@ model Team { members TeamUser[] links Link[] pixels Pixel[] + boards Board[] @@index([accessCode]) @@map("team") @@ -316,3 +318,25 @@ model Pixel { @@index([createdAt]) @@map("pixel") } + +model Board { + id String @id() @unique() @map("board_id") @db.Uuid + type String @db.VarChar(50) + name String @db.VarChar(200) + description String @db.VarChar(500) + parameters Json + slug String @unique() @db.VarChar(100) + userId String? @map("user_id") @db.Uuid + teamId String? @map("team_id") @db.Uuid + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) + + user User? @relation("user", fields: [userId], references: [id]) + team Team? @relation(fields: [teamId], references: [id]) + + @@index([slug]) + @@index([userId]) + @@index([teamId]) + @@index([createdAt]) + @@map("board") +} diff --git a/src/app/(main)/SideNav.tsx b/src/app/(main)/SideNav.tsx index 1ecb58dbc..73d598990 100644 --- a/src/app/(main)/SideNav.tsx +++ b/src/app/(main)/SideNav.tsx @@ -10,7 +10,7 @@ import { import Link from 'next/link'; import type { Key } from 'react'; import { useGlobalState, useMessages, useNavigation } from '@/components/hooks'; -import { Globe, Grid2x2, LinkIcon, PanelLeft } from '@/components/icons'; +import { Globe, Grid2x2, LayoutDashboard, LinkIcon, PanelLeft } from '@/components/icons'; import { LanguageButton } from '@/components/input/LanguageButton'; import { NavButton } from '@/components/input/NavButton'; import { PanelButton } from '@/components/input/PanelButton'; @@ -24,6 +24,12 @@ export function SideNav(props: SidebarProps) { const hasNav = !!(websiteId || pathname.startsWith('/admin') || pathname.includes('/settings')); const links = [ + { + id: 'boards', + label: formatMessage(labels.boards), + path: '/boards', + icon: , + }, { id: 'websites', label: formatMessage(labels.websites), From a39ebffd8b137f4788568de35934dd4c59c4f5a2 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 29 Nov 2025 15:59:01 -0800 Subject: [PATCH 004/412] Boards components. --- src/app/(main)/boards/BoardAddButton.tsx | 2 +- src/app/(main)/boards/BoardAddForm.tsx | 28 ++++--- src/app/(main)/boards/BoardsDataTable.tsx | 14 ++++ src/app/(main)/boards/BoardsPage.tsx | 19 ++++- src/app/(main)/boards/BoardsTable.tsx | 29 +++++++ src/app/(main)/boards/[boardId]/Board.tsx | 10 --- .../(main)/boards/[boardId]/BoardHeader.tsx | 43 ++++++++++ src/app/(main)/boards/[boardId]/BoardPage.tsx | 17 ++++ src/app/(main)/boards/[boardId]/page.tsx | 4 +- src/app/api/boards/[boardId]/route.ts | 78 +++++++++++++++++++ src/app/api/boards/route.ts | 61 +++++++++++++++ src/app/api/teams/[teamId]/boards/route.ts | 29 +++++++ src/components/common/DataGrid.tsx | 2 +- src/components/common/LoadingPanel.tsx | 2 + src/components/hooks/index.ts | 1 + .../hooks/queries/useBoardsQuery.ts | 17 ++++ src/permissions/board.ts | 64 +++++++++++++++ src/permissions/index.ts | 1 + src/queries/prisma/board.ts | 61 +++++++++++++++ src/queries/prisma/index.ts | 1 + 20 files changed, 450 insertions(+), 33 deletions(-) create mode 100644 src/app/(main)/boards/BoardsDataTable.tsx create mode 100644 src/app/(main)/boards/BoardsTable.tsx delete mode 100644 src/app/(main)/boards/[boardId]/Board.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardHeader.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardPage.tsx create mode 100644 src/app/api/boards/[boardId]/route.ts create mode 100644 src/app/api/boards/route.ts create mode 100644 src/app/api/teams/[teamId]/boards/route.ts create mode 100644 src/components/hooks/queries/useBoardsQuery.ts create mode 100644 src/permissions/board.ts create mode 100644 src/queries/prisma/board.ts diff --git a/src/app/(main)/boards/BoardAddButton.tsx b/src/app/(main)/boards/BoardAddButton.tsx index f9f80f4d7..dd25dbf30 100644 --- a/src/app/(main)/boards/BoardAddButton.tsx +++ b/src/app/(main)/boards/BoardAddButton.tsx @@ -16,7 +16,7 @@ export function BoardAddButton() { return ( - + + + ); +} diff --git a/src/app/(main)/boards/[boardId]/BoardPage.tsx b/src/app/(main)/boards/[boardId]/BoardPage.tsx new file mode 100644 index 000000000..ad6a9d302 --- /dev/null +++ b/src/app/(main)/boards/[boardId]/BoardPage.tsx @@ -0,0 +1,17 @@ +'use client'; +import { Column } from '@umami/react-zen'; +import { BoardHeader } from '@/app/(main)/boards/[boardId]/BoardHeader'; +import { PageBody } from '@/components/common/PageBody'; +import { useMessages } from '@/components/hooks'; + +export function BoardPage() { + const { formatMessage, labels } = useMessages(); + + return ( + + + + + + ); +} diff --git a/src/app/(main)/boards/[boardId]/page.tsx b/src/app/(main)/boards/[boardId]/page.tsx index 2cb076a5e..82300eb63 100644 --- a/src/app/(main)/boards/[boardId]/page.tsx +++ b/src/app/(main)/boards/[boardId]/page.tsx @@ -1,10 +1,10 @@ import type { Metadata } from 'next'; -import { Board } from './Board'; +import { BoardPage } from './BoardPage'; export default async function ({ params }: { params: Promise<{ boardId: string }> }) { const { boardId } = await params; - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/api/boards/[boardId]/route.ts b/src/app/api/boards/[boardId]/route.ts new file mode 100644 index 000000000..a5dfd2aa3 --- /dev/null +++ b/src/app/api/boards/[boardId]/route.ts @@ -0,0 +1,78 @@ +import { z } from 'zod'; +import { SHARE_ID_REGEX } from '@/lib/constants'; +import { parseRequest } from '@/lib/request'; +import { badRequest, json, ok, serverError, unauthorized } from '@/lib/response'; +import { canDeleteBoard, canUpdateBoard, canViewBoard } from '@/permissions'; +import { deleteBoard, getBoard, updateBoard } from '@/queries/prisma'; + +export async function GET(request: Request, { params }: { params: Promise<{ boardId: string }> }) { + const { auth, error } = await parseRequest(request); + + if (error) { + return error(); + } + + const { boardId } = await params; + + if (!(await canViewBoard(auth, boardId))) { + return unauthorized(); + } + + const board = await getBoard(boardId); + + return json(board); +} + +export async function POST(request: Request, { params }: { params: Promise<{ boardId: string }> }) { + const schema = z.object({ + name: z.string().optional(), + domain: z.string().optional(), + shareId: z.string().regex(SHARE_ID_REGEX).nullable().optional(), + }); + + const { auth, body, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { boardId } = await params; + const { name, domain, shareId } = body; + + if (!(await canUpdateBoard(auth, boardId))) { + return unauthorized(); + } + + try { + const board = await updateBoard(boardId, { name, domain, shareId }); + + return Response.json(board); + } catch (e: any) { + if (e.message.toLowerCase().includes('unique constraint') && e.message.includes('slug')) { + return badRequest({ message: 'That slug is already taken.' }); + } + + return serverError(e); + } +} + +export async function DELETE( + request: Request, + { params }: { params: Promise<{ boardId: string }> }, +) { + const { auth, error } = await parseRequest(request); + + if (error) { + return error(); + } + + const { boardId } = await params; + + if (!(await canDeleteBoard(auth, boardId))) { + return unauthorized(); + } + + await deleteBoard(boardId); + + return ok(); +} diff --git a/src/app/api/boards/route.ts b/src/app/api/boards/route.ts new file mode 100644 index 000000000..53c7f25c6 --- /dev/null +++ b/src/app/api/boards/route.ts @@ -0,0 +1,61 @@ +import { z } from 'zod'; +import { uuid } from '@/lib/crypto'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { pagingParams, searchParams } from '@/lib/schema'; +import { canCreateTeamWebsite, canCreateWebsite } from '@/permissions'; +import { createBoard, getUserBoards } from '@/queries/prisma'; + +export async function GET(request: Request) { + const schema = z.object({ + ...pagingParams, + ...searchParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const filters = await getQueryFilters(query); + + const boards = await getUserBoards(auth.user.id, filters); + + return json(boards); +} + +export async function POST(request: Request) { + const schema = z.object({ + type: z.string(), + name: z.string().max(100), + description: z.string().max(500).optional(), + slug: z.string().max(100), + userId: z.uuid().nullable().optional(), + teamId: z.uuid().nullable().optional(), + }); + + const { auth, body, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { teamId } = body; + + if ((teamId && !(await canCreateTeamWebsite(auth, teamId))) || !(await canCreateWebsite(auth))) { + return unauthorized(); + } + + const data = { + ...body, + id: uuid(), + parameters: {}, + slug: uuid(), + userId: !teamId ? auth.user.id : undefined, + }; + + const result = await createBoard(data); + + return json(result); +} diff --git a/src/app/api/teams/[teamId]/boards/route.ts b/src/app/api/teams/[teamId]/boards/route.ts new file mode 100644 index 000000000..daac2040d --- /dev/null +++ b/src/app/api/teams/[teamId]/boards/route.ts @@ -0,0 +1,29 @@ +import { z } from 'zod'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { pagingParams, searchParams } from '@/lib/schema'; +import { canViewTeam } from '@/permissions'; +import { getTeamPixels } from '@/queries/prisma'; + +export async function GET(request: Request, { params }: { params: Promise<{ teamId: string }> }) { + const schema = z.object({ + ...pagingParams, + ...searchParams, + }); + const { teamId } = await params; + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + if (!(await canViewTeam(auth, teamId))) { + return unauthorized(); + } + + const filters = await getQueryFilters(query); + + const websites = await getTeamPixels(teamId, filters); + + return json(websites); +} diff --git a/src/components/common/DataGrid.tsx b/src/components/common/DataGrid.tsx index 7e07b8dcd..b98367e2f 100644 --- a/src/components/common/DataGrid.tsx +++ b/src/components/common/DataGrid.tsx @@ -76,7 +76,7 @@ export function DataGrid({ )} { + return get(teamId ? `/teams/${teamId}/boards` : '/boards', pageParams); + }, + ...options, + }); +} diff --git a/src/permissions/board.ts b/src/permissions/board.ts new file mode 100644 index 000000000..c425de871 --- /dev/null +++ b/src/permissions/board.ts @@ -0,0 +1,64 @@ +import { hasPermission } from '@/lib/auth'; +import { PERMISSIONS } from '@/lib/constants'; +import type { Auth } from '@/lib/types'; +import { getBoard, getTeamUser } from '@/queries/prisma'; + +export async function canViewBoard({ user }: Auth, boardId: string) { + if (user?.isAdmin) { + return true; + } + + const board = await getBoard(boardId); + + if (board.userId) { + return user.id === board.userId; + } + + if (board.teamId) { + const teamUser = await getTeamUser(board.teamId, user.id); + + return !!teamUser; + } + + return false; +} + +export async function canUpdateBoard({ user }: Auth, boardId: string) { + if (user.isAdmin) { + return true; + } + + const board = await getBoard(boardId); + + if (board.userId) { + return user.id === board.userId; + } + + if (board.teamId) { + const teamUser = await getTeamUser(board.teamId, user.id); + + return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteUpdate); + } + + return false; +} + +export async function canDeleteBoard({ user }: Auth, boardId: string) { + if (user.isAdmin) { + return true; + } + + const board = await getBoard(boardId); + + if (board.userId) { + return user.id === board.userId; + } + + if (board.teamId) { + const teamUser = await getTeamUser(board.teamId, user.id); + + return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteDelete); + } + + return false; +} diff --git a/src/permissions/index.ts b/src/permissions/index.ts index a70808e69..12fbca8af 100644 --- a/src/permissions/index.ts +++ b/src/permissions/index.ts @@ -1,3 +1,4 @@ +export * from './board'; export * from './link'; export * from './pixel'; export * from './report'; diff --git a/src/queries/prisma/board.ts b/src/queries/prisma/board.ts new file mode 100644 index 000000000..9f2037f38 --- /dev/null +++ b/src/queries/prisma/board.ts @@ -0,0 +1,61 @@ +import type { Prisma } from '@/generated/prisma/client'; +import prisma from '@/lib/prisma'; +import type { QueryFilters } from '@/lib/types'; + +export async function findBoard(criteria: Prisma.BoardFindUniqueArgs) { + return prisma.client.board.findUnique(criteria); +} + +export async function getBoard(boardId: string) { + return findBoard({ + where: { + id: boardId, + }, + }); +} + +export async function getBoards(criteria: Prisma.BoardFindManyArgs, filters: QueryFilters = {}) { + const { search } = filters; + const { getSearchParameters, pagedQuery } = prisma; + + const where: Prisma.BoardWhereInput = { + ...criteria.where, + ...getSearchParameters(search, [{ name: 'contains' }, { description: 'contains' }]), + }; + + return pagedQuery('board', { ...criteria, where }, filters); +} + +export async function getUserBoards(userId: string, filters?: QueryFilters) { + return getBoards( + { + where: { + userId, + }, + }, + filters, + ); +} + +export async function getTeamBoards(teamId: string, filters?: QueryFilters) { + return getBoards( + { + where: { + teamId, + }, + }, + filters, + ); +} + +export async function createBoard(data: Prisma.BoardUncheckedCreateInput) { + return prisma.client.board.create({ data }); +} + +export async function updateBoard(boardId: string, data: any) { + return prisma.client.board.update({ where: { id: boardId }, data }); +} + +export async function deleteBoard(boardId: string) { + return prisma.client.board.delete({ where: { id: boardId } }); +} diff --git a/src/queries/prisma/index.ts b/src/queries/prisma/index.ts index b9730f511..233cf6712 100644 --- a/src/queries/prisma/index.ts +++ b/src/queries/prisma/index.ts @@ -1,3 +1,4 @@ +export * from './board'; export * from './link'; export * from './pixel'; export * from './report'; From aaa8b5b6c9b0eb6d55284d63127d54879e7f613f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:37:01 +0000 Subject: [PATCH 005/412] Bump jws from 3.2.2 to 3.2.3 Bumps [jws](https://github.com/brianloveswords/node-jws) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/brianloveswords/node-jws/releases) - [Changelog](https://github.com/auth0/node-jws/blob/master/CHANGELOG.md) - [Commits](https://github.com/brianloveswords/node-jws/compare/v3.2.2...v3.2.3) --- updated-dependencies: - dependency-name: jws dependency-version: 3.2.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10eed8210..d68fed5e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -331,8 +331,6 @@ importers: specifier: ^5.9.3 version: 5.9.3 - dist: {} - packages: '@ampproject/remapping@2.3.0': From 83b03d682ca21550497873ce088bd71092ed95eb Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 4 Dec 2025 12:27:44 -0800 Subject: [PATCH 006/412] fix getRevenue case-insensitivity bug --- src/queries/sql/reports/getRevenue.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/queries/sql/reports/getRevenue.ts b/src/queries/sql/reports/getRevenue.ts index fa25078c3..ebde8bb1b 100644 --- a/src/queries/sql/reports/getRevenue.ts +++ b/src/queries/sql/reports/getRevenue.ts @@ -62,7 +62,7 @@ async function relationalQuery( ${joinSessionQuery} where revenue.website_id = {{websiteId::uuid}} and revenue.created_at between {{startDate}} and {{endDate}} - and revenue.currency = upper({{currency}}) + and upper(revenue.currency) = {{currency}} ${filterQuery} group by x, t order by t @@ -83,7 +83,7 @@ async function relationalQuery( ${cohortQuery} where revenue.website_id = {{websiteId::uuid}} and revenue.created_at between {{startDate}} and {{endDate}} - and revenue.currency = upper({{currency}}) + and upper(revenue.currency) = {{currency}} ${filterQuery} group by session.country `, @@ -102,7 +102,7 @@ async function relationalQuery( ${joinSessionQuery} where revenue.website_id = {{websiteId::uuid}} and revenue.created_at between {{startDate}} and {{endDate}} - and revenue.currency = upper({{currency}}) + and upper(revenue.currency) = {{currency}} ${filterQuery} `, queryParams, @@ -154,7 +154,7 @@ async function clickhouseQuery( ${cohortQuery} where website_revenue.website_id = {websiteId:UUID} and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64} - and website_revenue.currency = upper({currency:String}) + and upper(website_revenue.currency) = {currency:String} ${filterQuery} group by x, t order by t @@ -182,7 +182,7 @@ async function clickhouseQuery( ${cohortQuery} where website_revenue.website_id = {websiteId:UUID} and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64} - and website_revenue.currency = upper({currency:String}) + and upper(website_revenue.currency) = {currency:String} ${filterQuery} group by website_event.country order by value desc @@ -205,7 +205,7 @@ async function clickhouseQuery( ${cohortQuery} where website_revenue.website_id = {websiteId:UUID} and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64} - and website_revenue.currency = upper({currency:String}) + aand upper(website_revenue.currency) = {currency:String} ${filterQuery} `, queryParams, From 220c2af34495e71491235c360bfe7f36c9a3956d Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 5 Dec 2025 09:18:53 -0800 Subject: [PATCH 007/412] fix revenue type --- src/queries/sql/reports/getRevenue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries/sql/reports/getRevenue.ts b/src/queries/sql/reports/getRevenue.ts index ebde8bb1b..19b75d429 100644 --- a/src/queries/sql/reports/getRevenue.ts +++ b/src/queries/sql/reports/getRevenue.ts @@ -205,7 +205,7 @@ async function clickhouseQuery( ${cohortQuery} where website_revenue.website_id = {websiteId:UUID} and website_revenue.created_at between {startDate:DateTime64} and {endDate:DateTime64} - aand upper(website_revenue.currency) = {currency:String} + and upper(website_revenue.currency) = {currency:String} ${filterQuery} `, queryParams, From d227bc369f2fd2f69125db3aebc4be853949420e Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 5 Dec 2025 16:49:08 -0800 Subject: [PATCH 008/412] Progress check-in. --- package.json | 18 +- pnpm-lock.yaml | 522 ++++++++++++++---- prisma/schema.prisma | 1 - src/app/(main)/boards/BoardProvider.tsx | 21 + src/app/(main)/boards/[boardId]/BoardBody.tsx | 3 + .../(main)/boards/[boardId]/BoardHeader.tsx | 45 +- src/app/(main)/boards/[boardId]/BoardPage.tsx | 18 +- src/components/boards/Board.tsx | 9 - src/components/hooks/context/useBoard.ts | 6 + src/components/hooks/index.ts | 2 + src/components/hooks/queries/useBoardQuery.ts | 17 + 11 files changed, 519 insertions(+), 143 deletions(-) create mode 100644 src/app/(main)/boards/BoardProvider.tsx create mode 100644 src/app/(main)/boards/[boardId]/BoardBody.tsx delete mode 100644 src/components/boards/Board.tsx create mode 100644 src/components/hooks/context/useBoard.ts create mode 100644 src/components/hooks/queries/useBoardQuery.ts diff --git a/package.json b/package.json index 09a691352..f425d9cf9 100644 --- a/package.json +++ b/package.json @@ -67,14 +67,14 @@ "@dicebear/core": "^9.2.3", "@fontsource/inter": "^5.2.8", "@hello-pangea/dnd": "^17.0.0", - "@prisma/adapter-pg": "^6.18.0", - "@prisma/client": "^6.18.0", - "@prisma/extension-read-replicas": "^0.4.1", + "@prisma/adapter-pg": "^7.1.0", + "@prisma/client": "^7.1.0", + "@prisma/extension-read-replicas": "^0.5.0", "@react-spring/web": "^10.0.3", "@svgr/cli": "^8.1.0", - "@tanstack/react-query": "^5.90.11", - "@umami/react-zen": "^0.211.0", - "@umami/redis-client": "^0.29.0", + "@tanstack/react-query": "^5.90.12", + "@umami/react-zen": "^0.216.0", + "@umami/redis-client": "^0.30.0", "bcryptjs": "^3.0.2", "chalk": "^5.6.2", "chart.js": "^4.5.1", @@ -97,7 +97,7 @@ "is-docker": "^3.0.0", "is-localhost-ip": "^2.0.0", "isbot": "^5.1.31", - "jsonwebtoken": "^9.0.2", + "jsonwebtoken": "^9.0.3", "jszip": "^3.10.1", "kafkajs": "^2.1.0", "lucide-react": "^0.543.0", @@ -107,7 +107,7 @@ "npm-run-all": "^4.1.5", "papaparse": "^5.5.3", "pg": "^8.16.3", - "prisma": "^6.18.0", + "prisma": "^7.1.0", "pure-rand": "^7.0.1", "react": "^19.2.1", "react-dom": "^19.2.1", @@ -121,7 +121,7 @@ "serialize-error": "^12.0.0", "thenby": "^1.3.4", "ua-parser-js": "^2.0.6", - "uuid": "^11.1.0", + "uuid": "^13.0.0", "zod": "^4.1.13", "zustand": "^5.0.9" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10eed8210..c4badb24e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,14 +27,14 @@ importers: specifier: ^17.0.0 version: 17.0.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@prisma/adapter-pg': - specifier: ^6.18.0 - version: 6.19.0 + specifier: ^7.1.0 + version: 7.1.0 '@prisma/client': - specifier: ^6.18.0 - version: 6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3) + specifier: ^7.1.0 + version: 7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3) '@prisma/extension-read-replicas': - specifier: ^0.4.1 - version: 0.4.1(@prisma/client@6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3)) + specifier: ^0.5.0 + version: 0.5.0(@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3)) '@react-spring/web': specifier: ^10.0.3 version: 10.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -42,14 +42,14 @@ importers: specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) '@tanstack/react-query': - specifier: ^5.90.11 - version: 5.90.11(react@19.2.1) + specifier: ^5.90.12 + version: 5.90.12(react@19.2.1) '@umami/react-zen': - specifier: ^0.211.0 - version: 0.211.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1)) + specifier: ^0.216.0 + version: 0.216.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1)) '@umami/redis-client': - specifier: ^0.29.0 - version: 0.29.0 + specifier: ^0.30.0 + version: 0.30.0 bcryptjs: specifier: ^3.0.2 version: 3.0.3 @@ -117,8 +117,8 @@ importers: specifier: ^5.1.31 version: 5.1.32 jsonwebtoken: - specifier: ^9.0.2 - version: 9.0.2 + specifier: ^9.0.3 + version: 9.0.3 jszip: specifier: ^3.10.1 version: 3.10.1 @@ -147,8 +147,8 @@ importers: specifier: ^8.16.3 version: 8.16.3 prisma: - specifier: ^6.18.0 - version: 6.19.0(typescript@5.9.3) + specifier: ^7.1.0 + version: 7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3) pure-rand: specifier: ^7.0.1 version: 7.0.1 @@ -189,8 +189,8 @@ importers: specifier: ^2.0.6 version: 2.0.6 uuid: - specifier: ^11.1.0 - version: 11.1.0 + specifier: ^13.0.0 + version: 13.0.0 zod: specifier: ^4.1.13 version: 4.1.13 @@ -561,6 +561,18 @@ packages: cpu: [x64] os: [win32] + '@chevrotain/cst-dts-gen@10.5.0': + resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==} + + '@chevrotain/gast@10.5.0': + resolution: {integrity: sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==} + + '@chevrotain/types@10.5.0': + resolution: {integrity: sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==} + + '@chevrotain/utils@10.5.0': + resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} + '@clickhouse/client-common@1.14.0': resolution: {integrity: sha512-CyUcv2iCkZ1A++vmOSufYRpHR3aAWVfbrWed7ATzf0yyx/BW/2SEqlL07vBpSRa3BIkQe/DSOHVv8JkWZpUOwQ==} @@ -889,6 +901,20 @@ packages: peerDependencies: '@dicebear/core': ^9.0.0 + '@electric-sql/pglite-socket@0.0.6': + resolution: {integrity: sha512-6RjmgzphIHIBA4NrMGJsjNWK4pu+bCWJlEWlwcxFTVY3WT86dFpKwbZaGWZV6C5Rd7sCk1Z0CI76QEfukLAUXw==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.3.2 + + '@electric-sql/pglite-tools@0.2.7': + resolution: {integrity: sha512-9dAccClqxx4cZB+Ar9B+FZ5WgxDc/Xvl9DPrTWv+dYTf0YNubLzi4wHHRGRGhrJv15XwnyKcGOZAP1VXSneSUg==} + peerDependencies: + '@electric-sql/pglite': 0.3.2 + + '@electric-sql/pglite@0.3.2': + resolution: {integrity: sha512-zfWWa+V2ViDCY/cmUfRqeWY1yLto+EpxjXnZzenB1TyxsTiXaTWeZFIZw6mac52BsuQm0RjCnisjBtdBaXOI6w==} + '@emnapi/runtime@1.5.0': resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} @@ -1286,6 +1312,12 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 + '@hono/node-server@1.19.6': + resolution: {integrity: sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -1689,6 +1721,10 @@ packages: '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + '@mrleebo/prisma-ast@0.12.1': + resolution: {integrity: sha512-JwqeCQ1U3fvccttHZq7Tk0m/TMC6WcFAQZdukypW3AzlJYKYTGNVd1ANU2GuhKnv4UQuOFj3oAl0LLG/gxFN1w==} + engines: {node: '>=16'} + '@netlify/plugin-nextjs@5.15.1': resolution: {integrity: sha512-HXm94tteOuA0FYwhkxjYIPe0zta+Dsu0wz7LnhfqVlaYcRaOLjHtd2vgfmpz3np/fx9TQg3gCfqGkXt2a9i7Aw==} engines: {node: '>=18.0.0'} @@ -1811,46 +1847,68 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@prisma/adapter-pg@6.19.0': - resolution: {integrity: sha512-F8f2kvU+igmxERA9oM+D2maMaxrST1P6vO7ayvdlAdcJI47nKNPdkLBGZKic9otghfA9CQnjNOGB56q2VXqnHw==} + '@prisma/adapter-pg@7.1.0': + resolution: {integrity: sha512-DSAnUwkKfX4bUzhkrjGN4IBQzwg0nvFw2W17H0Oa532I5w9nLtTJ9mAEGDs1nUBEGRAsa0c7qsf8CSgfJ4DsBQ==} - '@prisma/client@6.19.0': - resolution: {integrity: sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==} - engines: {node: '>=18.18'} + '@prisma/client-runtime-utils@7.1.0': + resolution: {integrity: sha512-39xmeBrNTN40FzF34aJMjfX1PowVCqoT3UKUWBBSP3aXV05NRqGBC3x2wCDs96ti6ZgdiVzqnRDHtbzU8X+lPQ==} + + '@prisma/client@7.1.0': + resolution: {integrity: sha512-qf7GPYHmS/xybNiSOpzv9wBo+UwqfL2PeyX+08v+KVHDI0AlSCQIh5bBySkH3alu06NX9wy98JEnckhMHoMFfA==} + engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' - typescript: '>=5.1.0' + typescript: '>=5.4.0' peerDependenciesMeta: prisma: optional: true typescript: optional: true - '@prisma/config@6.19.0': - resolution: {integrity: sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==} + '@prisma/config@7.1.0': + resolution: {integrity: sha512-Uz+I43Wn1RYNHtuYtOhOnUcNMWp2Pd3GUDDKs37xlHptCGpzEG3MRR9L+8Y2ISMsMI24z/Ni+ww6OB/OO8M0sQ==} - '@prisma/debug@6.19.0': - resolution: {integrity: sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==} + '@prisma/debug@6.8.2': + resolution: {integrity: sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==} - '@prisma/driver-adapter-utils@6.19.0': - resolution: {integrity: sha512-VAC/wFebV569Jk7iEqzLxekM2A5toKYAr6cPM2KWVHiRHgyjsh/IHf++Xo67q8uor/JxY8mwOuyQyuxkstSf5w==} + '@prisma/debug@7.1.0': + resolution: {integrity: sha512-pPAckG6etgAsEBusmZiFwM9bldLSNkn++YuC4jCTJACdK5hLOVnOzX7eSL2FgaU6Gomd6wIw21snUX2dYroMZQ==} - '@prisma/engines-version@6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773': - resolution: {integrity: sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==} + '@prisma/dev@0.15.0': + resolution: {integrity: sha512-KhWaipnFlS/fWEs6I6Oqjcy2S08vKGmxJ5LexqUl/3Ve0EgLUsZwdKF0MvqPM5F5ttw8GtfZarjM5y7VLwv9Ow==} - '@prisma/engines@6.19.0': - resolution: {integrity: sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==} + '@prisma/driver-adapter-utils@7.1.0': + resolution: {integrity: sha512-AlVLzeXkw81+47MvQ9M8DvTiHkRfJ8xzklTbYjpskb0cTTDVHboTI/OVwT6Wcep/bNvfLKJYO0nylBiM5rxgww==} - '@prisma/extension-read-replicas@0.4.1': - resolution: {integrity: sha512-mCMDloqUKUwx2o5uedTs1FHX3Nxdt1GdRMoeyp1JggjiwOALmIYWhxfIN08M2BZ0w8SKwvJqicJZMjkQYkkijw==} + '@prisma/engines-version@7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba': + resolution: {integrity: sha512-qZUevUh+yPhGT28rDQnV8V2kLnFjirzhVD67elRPIJHRsUV/mkII10HSrJrhK/U2GYgAxXR2VEREtq7AsfS8qw==} + + '@prisma/engines@7.1.0': + resolution: {integrity: sha512-KQlraOybdHAzVv45KWKJzpR9mJLkib7/TyApQpqrsL7FUHfgjIcy8jrVGt3iNfG6/GDDl+LNlJ84JSQwIfdzxA==} + + '@prisma/extension-read-replicas@0.5.0': + resolution: {integrity: sha512-t0kLjqFMte4wwGrZFhya4iFoyoOY4kjlyyE60WXZL66PqP6PcBpW/35eKb/3UcxgjJxcDlaJKfmGokFLOyafiQ==} peerDependencies: - '@prisma/client': ^6.5.0 + '@prisma/client': ^7.0.0 - '@prisma/fetch-engine@6.19.0': - resolution: {integrity: sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==} + '@prisma/fetch-engine@7.1.0': + resolution: {integrity: sha512-GZYF5Q8kweXWGfn87hTu17kw7x1DgnehgKoE4Zg1BmHYF3y1Uu0QRY/qtSE4veH3g+LW8f9HKqA0tARG66bxxQ==} - '@prisma/get-platform@6.19.0': - resolution: {integrity: sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==} + '@prisma/get-platform@6.8.2': + resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==} + + '@prisma/get-platform@7.1.0': + resolution: {integrity: sha512-lq8hMdjKiZftuT5SssYB3EtQj8+YjL24/ZTLflQqzFquArKxBcyp6Xrblto+4lzIKJqnpOjfMiBjMvl7YuD7+Q==} + + '@prisma/query-plan-executor@6.18.0': + resolution: {integrity: sha512-jZ8cfzFgL0jReE1R10gT8JLHtQxjWYLiQ//wHmVYZ2rVkFHoh0DT8IXsxcKcFlfKN7ak7k6j0XMNn2xVNyr5cA==} + + '@prisma/studio-core@0.8.2': + resolution: {integrity: sha512-/iAEWEUpTja+7gVMu1LtR2pPlvDmveAwMHdTWbDeGlT7yiv0ZTCPpmeAGdq/Y9aJ9Zj1cEGBXGRbmmNPj022PQ==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 '@react-aria/autocomplete@3.0.0-rc.3': resolution: {integrity: sha512-vemf7h3hvIDk3MxiiPryysfYgJDg8R72X46dRIeg0+cXKYxjPYou64/DTucSV2z5J6RC5JalINu0jIDaLhEILw==} @@ -2817,11 +2875,11 @@ packages: '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} - '@tanstack/query-core@5.90.11': - resolution: {integrity: sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==} + '@tanstack/query-core@5.90.12': + resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} - '@tanstack/react-query@5.90.11': - resolution: {integrity: sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==} + '@tanstack/react-query@5.90.12': + resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==} peerDependencies: react: ^18 || ^19 @@ -2950,11 +3008,11 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@umami/react-zen@0.211.0': - resolution: {integrity: sha512-e9dfsmMYpClYU/xQ+nwFo4ktAJc6eth4k6lpdD4j47FD5PaMfSY1FK1qJ7yq/JVN0Ydomc8cuWBDZbHpG4sQmQ==} + '@umami/react-zen@0.216.0': + resolution: {integrity: sha512-nDx+RYGs7Xk3Pqhza0b059mKXb4CSPstrR7kIIFKgZLA5w6m4JWMwxleDX+RXAEAROjDRH3RYUz/lPL96OkhLg==} - '@umami/redis-client@0.29.0': - resolution: {integrity: sha512-Jaqh++jskqDB7ny75pfC02OvKp1JTS4asGDsFrRL3qy8sxL3PAl9+/mybCJe4/6vWrXDJKqpgkSfUDJq2bFjyw==} + '@umami/redis-client@0.30.0': + resolution: {integrity: sha512-pqeMPdEFMH+9GDpiQd5MdRdTppif4vPl/sp8Y9hPY277g/UFlJAbCUJluESmZRBHjFdXtBPtLzQkxjvdjlRzuQ==} '@vue/compiler-core@3.5.18': resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==} @@ -3123,6 +3181,10 @@ packages: aws-sign2@0.7.0: resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} @@ -3316,6 +3378,9 @@ packages: resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} engines: {node: '>= 0.8.0'} + chevrotain@10.5.0: + resolution: {integrity: sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -3761,6 +3826,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -4136,6 +4205,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + generic-names@4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} @@ -4163,6 +4235,9 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-port-please@3.1.2: + resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -4251,6 +4326,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + handlebars@4.7.8: resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} engines: {node: '>=0.4.7'} @@ -4298,6 +4376,10 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.10.6: + resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==} + engines: {node: '>=16.9.0'} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -4316,6 +4398,9 @@ packages: resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==} engines: {node: '>=0.10'} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + human-signals@1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} engines: {node: '>=8.12.0'} @@ -4329,6 +4414,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + icss-replace-symbols@1.1.0: resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==} @@ -4558,6 +4647,9 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -4873,8 +4965,8 @@ packages: jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} jsprim@2.0.2: @@ -4884,11 +4976,11 @@ packages: jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} kafkajs@2.2.4: resolution: {integrity: sha512-j/YeapB1vfPT2iOIUn/vxdyKEuhuY2PxMBvf5JWux6iSaukAccrMtXEY/Lb7OvavDhOWME589bpLrEdnVHjfjA==} @@ -5033,6 +5125,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -5058,6 +5153,14 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lru.min@1.1.3: + resolution: {integrity: sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lucide-react@0.543.0: resolution: {integrity: sha512-fpVfuOQO0V3HBaOA1stIiP/A2fPCXHIleRZL16Mx3HmjTYwNSbimhnFBygs2CAfU1geexMX5ItUcWBGUaqw5CA==} peerDependencies: @@ -5228,9 +5331,17 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + nano-spawn@2.0.0: resolution: {integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==} engines: {node: '>=20.17'} @@ -6034,6 +6145,10 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -6051,13 +6166,16 @@ packages: resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - prisma@6.19.0: - resolution: {integrity: sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==} - engines: {node: '>=18.18'} + prisma@7.1.0: + resolution: {integrity: sha512-dy/3urE4JjhdiW5b09pGjVhGI7kPESK2VlCDrCqeYK5m5SslAtG5FCGnZWP7E8Sdg+Ow1wV2mhJH5RTFL5gEsw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true peerDependencies: - typescript: '>=5.1.0' + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' peerDependenciesMeta: + better-sqlite3: + optional: true typescript: optional: true @@ -6079,6 +6197,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + proxy-from-env@1.0.0: resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} @@ -6141,8 +6262,8 @@ packages: peerDependencies: react: '>=16.13.1' - react-hook-form@7.67.0: - resolution: {integrity: sha512-E55EOwKJHHIT/I6J9DmQbCWToAYSw9nN5R57MZw9rMtjh+YQreMDxRLfdjfxQbiJ3/qbg3Z02wGzBX4M+5fMtQ==} + react-hook-form@7.68.0: + resolution: {integrity: sha512-oNN3fjrZ/Xo40SWlHf1yCjlMK417JxoSJVUXQjGdvdRCU07NTFei1i1f8ApUAts+IVh14e4EdakeLEA+BEAs/Q==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -6263,10 +6384,16 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + regexp-to-ast@0.5.0: + resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + remeda@2.21.3: + resolution: {integrity: sha512-XXrZdLA10oEOQhLLzEJEiFFSKi21REGAkHdImIb4rt/XXy8ORGXh5HCcpUOsElfPNDb+X6TA/+wkh+p2KffYmg==} + request-ip@3.3.0: resolution: {integrity: sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==} @@ -6313,6 +6440,10 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -6417,6 +6548,9 @@ packages: engines: {node: '>=10'} hasBin: true + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serialize-error@12.0.0: resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} engines: {node: '>=18'} @@ -6563,6 +6697,10 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + sshpk@1.18.0: resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} engines: {node: '>=0.10.0'} @@ -6576,6 +6714,9 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -7041,8 +7182,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} hasBin: true uuid@8.3.2: @@ -7056,6 +7197,14 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -7194,6 +7343,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zeptomatch@2.0.2: + resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==} + zod@4.1.13: resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} @@ -7448,6 +7600,21 @@ snapshots: '@biomejs/cli-win32-x64@2.3.8': optional: true + '@chevrotain/cst-dts-gen@10.5.0': + dependencies: + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + + '@chevrotain/gast@10.5.0': + dependencies: + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + + '@chevrotain/types@10.5.0': {} + + '@chevrotain/utils@10.5.0': {} + '@clickhouse/client-common@1.14.0': {} '@clickhouse/client@1.14.0': @@ -7742,6 +7909,16 @@ snapshots: dependencies: '@dicebear/core': 9.2.4 + '@electric-sql/pglite-socket@0.0.6(@electric-sql/pglite@0.3.2)': + dependencies: + '@electric-sql/pglite': 0.3.2 + + '@electric-sql/pglite-tools@0.2.7(@electric-sql/pglite@0.3.2)': + dependencies: + '@electric-sql/pglite': 0.3.2 + + '@electric-sql/pglite@0.3.2': {} + '@emnapi/runtime@1.5.0': dependencies: tslib: 2.8.1 @@ -8036,6 +8213,10 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@hono/node-server@1.19.6(hono@4.10.6)': + dependencies: + hono: 4.10.6 + '@img/colour@1.0.0': optional: true @@ -8476,6 +8657,11 @@ snapshots: '@kurkle/color@0.3.4': {} + '@mrleebo/prisma-ast@0.12.1': + dependencies: + chevrotain: 10.5.0 + lilconfig: 2.1.0 + '@netlify/plugin-nextjs@5.15.1': {} '@next/env@15.5.7': {} @@ -8545,20 +8731,24 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@prisma/adapter-pg@6.19.0': + '@prisma/adapter-pg@7.1.0': dependencies: - '@prisma/driver-adapter-utils': 6.19.0 + '@prisma/driver-adapter-utils': 7.1.0 pg: 8.16.3 postgres-array: 3.0.4 transitivePeerDependencies: - pg-native - '@prisma/client@6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client-runtime-utils@7.1.0': {} + + '@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@prisma/client-runtime-utils': 7.1.0 optionalDependencies: - prisma: 6.19.0(typescript@5.9.3) + prisma: 7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3) typescript: 5.9.3 - '@prisma/config@6.19.0': + '@prisma/config@7.1.0': dependencies: c12: 3.1.0 deepmerge-ts: 7.1.5 @@ -8567,34 +8757,70 @@ snapshots: transitivePeerDependencies: - magicast - '@prisma/debug@6.19.0': {} + '@prisma/debug@6.8.2': {} - '@prisma/driver-adapter-utils@6.19.0': + '@prisma/debug@7.1.0': {} + + '@prisma/dev@0.15.0(typescript@5.9.3)': dependencies: - '@prisma/debug': 6.19.0 + '@electric-sql/pglite': 0.3.2 + '@electric-sql/pglite-socket': 0.0.6(@electric-sql/pglite@0.3.2) + '@electric-sql/pglite-tools': 0.2.7(@electric-sql/pglite@0.3.2) + '@hono/node-server': 1.19.6(hono@4.10.6) + '@mrleebo/prisma-ast': 0.12.1 + '@prisma/get-platform': 6.8.2 + '@prisma/query-plan-executor': 6.18.0 + foreground-child: 3.3.1 + get-port-please: 3.1.2 + hono: 4.10.6 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.21.3 + std-env: 3.9.0 + valibot: 1.2.0(typescript@5.9.3) + zeptomatch: 2.0.2 + transitivePeerDependencies: + - typescript - '@prisma/engines-version@6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773': {} - - '@prisma/engines@6.19.0': + '@prisma/driver-adapter-utils@7.1.0': dependencies: - '@prisma/debug': 6.19.0 - '@prisma/engines-version': 6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773 - '@prisma/fetch-engine': 6.19.0 - '@prisma/get-platform': 6.19.0 + '@prisma/debug': 7.1.0 - '@prisma/extension-read-replicas@0.4.1(@prisma/client@6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3))': - dependencies: - '@prisma/client': 6.19.0(prisma@6.19.0(typescript@5.9.3))(typescript@5.9.3) + '@prisma/engines-version@7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba': {} - '@prisma/fetch-engine@6.19.0': + '@prisma/engines@7.1.0': dependencies: - '@prisma/debug': 6.19.0 - '@prisma/engines-version': 6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773 - '@prisma/get-platform': 6.19.0 + '@prisma/debug': 7.1.0 + '@prisma/engines-version': 7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba + '@prisma/fetch-engine': 7.1.0 + '@prisma/get-platform': 7.1.0 - '@prisma/get-platform@6.19.0': + '@prisma/extension-read-replicas@0.5.0(@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3))': dependencies: - '@prisma/debug': 6.19.0 + '@prisma/client': 7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3) + + '@prisma/fetch-engine@7.1.0': + dependencies: + '@prisma/debug': 7.1.0 + '@prisma/engines-version': 7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba + '@prisma/get-platform': 7.1.0 + + '@prisma/get-platform@6.8.2': + dependencies: + '@prisma/debug': 6.8.2 + + '@prisma/get-platform@7.1.0': + dependencies: + '@prisma/debug': 7.1.0 + + '@prisma/query-plan-executor@6.18.0': {} + + '@prisma/studio-core@0.8.2(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@types/react': 19.2.7 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@react-aria/autocomplete@3.0.0-rc.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: @@ -9981,11 +10207,11 @@ snapshots: dependencies: tslib: 2.8.1 - '@tanstack/query-core@5.90.11': {} + '@tanstack/query-core@5.90.12': {} - '@tanstack/react-query@5.90.11(react@19.2.1)': + '@tanstack/react-query@5.90.12(react@19.2.1)': dependencies: - '@tanstack/query-core': 5.90.11 + '@tanstack/query-core': 5.90.12 react: 19.2.1 '@trysound/sax@0.2.0': {} @@ -10117,7 +10343,7 @@ snapshots: '@types/node': 24.10.1 optional: true - '@umami/react-zen@0.211.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1))': + '@umami/react-zen@0.216.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1))': dependencies: '@fontsource/jetbrains-mono': 5.2.8 '@internationalized/date': 3.10.0 @@ -10131,7 +10357,7 @@ snapshots: react: 19.2.1 react-aria-components: 1.13.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) react-dom: 19.2.1(react@19.2.1) - react-hook-form: 7.67.0(react@19.2.1) + react-hook-form: 7.68.0(react@19.2.1) react-icons: 5.5.0(react@19.2.1) thenby: 1.3.4 zustand: 5.0.9(@types/react@19.2.7)(immer@10.2.0)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)) @@ -10146,7 +10372,7 @@ snapshots: - sass - use-sync-external-store - '@umami/redis-client@0.29.0': + '@umami/redis-client@0.30.0': dependencies: debug: 4.4.3(supports-color@8.1.1) redis: 4.7.1 @@ -10332,6 +10558,8 @@ snapshots: aws-sign2@0.7.0: {} + aws-ssl-profiles@1.1.2: {} + aws4@1.13.2: {} babel-jest@29.7.0(@babel/core@7.28.3): @@ -10567,6 +10795,15 @@ snapshots: check-more-types@2.24.0: {} + chevrotain@10.5.0: + dependencies: + '@chevrotain/cst-dts-gen': 10.5.0 + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + '@chevrotain/utils': 10.5.0 + lodash: 4.17.21 + regexp-to-ast: 0.5.0 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -11063,6 +11300,8 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + destr@2.0.5: {} detect-browser@5.3.0: {} @@ -11572,6 +11811,10 @@ snapshots: functions-have-names@1.2.3: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + generic-names@4.0.0: dependencies: loader-utils: 3.3.1 @@ -11599,6 +11842,8 @@ snapshots: get-package-type@0.1.0: {} + get-port-please@3.1.2: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -11727,6 +11972,8 @@ snapshots: graceful-fs@4.2.11: {} + grammex@3.1.12: {} + handlebars@4.7.8: dependencies: minimist: 1.2.8 @@ -11768,6 +12015,8 @@ snapshots: dependencies: react-is: 16.13.1 + hono@4.10.6: {} + hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: @@ -11784,12 +12033,18 @@ snapshots: jsprim: 2.0.2 sshpk: 1.18.0 + http-status-codes@2.3.0: {} + human-signals@1.1.1: {} human-signals@2.1.0: {} husky@9.1.7: {} + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + icss-replace-symbols@1.1.0: {} icss-utils@5.1.0(postcss@8.5.6): @@ -11981,6 +12236,8 @@ snapshots: is-plain-object@5.0.0: {} + is-property@1.0.2: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -12496,9 +12753,9 @@ snapshots: jsonify@0.0.1: {} - jsonwebtoken@9.0.2: + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -12523,15 +12780,15 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 - jwa@1.4.2: + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - jws@3.2.2: + jws@4.0.1: dependencies: - jwa: 1.4.2 + jwa: 2.0.1 safe-buffer: 5.2.1 kafkajs@2.2.4: {} @@ -12671,6 +12928,8 @@ snapshots: strip-ansi: 7.1.2 wrap-ansi: 9.0.2 + long@5.3.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -12696,6 +12955,10 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + + lru.min@1.1.3: {} + lucide-react@0.543.0(react@19.2.1): dependencies: react: 19.2.1 @@ -12861,12 +13124,28 @@ snapshots: ms@2.1.3: {} + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.0 + long: 5.3.2 + lru.min: 1.1.3 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + nano-spawn@2.0.0: {} nanoid@3.3.11: {} @@ -13635,6 +13914,8 @@ snapshots: dependencies: xtend: 4.0.2 + postgres@3.4.7: {} + prettier@2.8.8: {} pretty-bytes@5.6.0: {} @@ -13651,14 +13932,21 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - prisma@6.19.0(typescript@5.9.3): + prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3): dependencies: - '@prisma/config': 6.19.0 - '@prisma/engines': 6.19.0 + '@prisma/config': 7.1.0 + '@prisma/dev': 0.15.0(typescript@5.9.3) + '@prisma/engines': 7.1.0 + '@prisma/studio-core': 0.8.2(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + mysql2: 3.15.3 + postgres: 3.4.7 optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: + - '@types/react' - magicast + - react + - react-dom process-nextick-args@2.0.1: {} @@ -13677,6 +13965,12 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + proxy-from-env@1.0.0: {} pump@3.0.3: @@ -13802,7 +14096,7 @@ snapshots: '@babel/runtime': 7.28.3 react: 19.2.1 - react-hook-form@7.67.0(react@19.2.1): + react-hook-form@7.68.0(react@19.2.1): dependencies: react: 19.2.1 @@ -13977,6 +14271,8 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + regexp-to-ast@0.5.0: {} + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -13986,6 +14282,10 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + remeda@2.21.3: + dependencies: + type-fest: 4.41.0 + request-ip@3.3.0: {} request-progress@3.0.0: @@ -14024,6 +14324,8 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 + retry@0.12.0: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -14161,6 +14463,8 @@ snapshots: semver@7.7.3: {} + seq-queue@0.0.5: {} + serialize-error@12.0.0: dependencies: type-fest: 4.41.0 @@ -14374,6 +14678,8 @@ snapshots: sprintf-js@1.0.3: {} + sqlstring@2.3.3: {} + sshpk@1.18.0: dependencies: asn1: 0.2.6 @@ -14392,6 +14698,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + std-env@3.9.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -14908,7 +15216,7 @@ snapshots: util-deprecate@1.0.2: {} - uuid@11.1.0: {} + uuid@13.0.0: {} uuid@8.3.2: {} @@ -14920,6 +15228,10 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + valibot@1.2.0(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 @@ -15092,6 +15404,10 @@ snapshots: yocto-queue@0.1.0: {} + zeptomatch@2.0.2: + dependencies: + grammex: 3.1.12 + zod@4.1.13: {} zustand@5.0.9(@types/react@19.2.7)(immer@10.2.0)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)): diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c0c03784d..6439b916b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -6,7 +6,6 @@ generator client { datasource db { provider = "postgresql" - url = env("DATABASE_URL") relationMode = "prisma" } diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx new file mode 100644 index 000000000..361366141 --- /dev/null +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -0,0 +1,21 @@ +'use client'; +import { Loading } from '@umami/react-zen'; +import { createContext, type ReactNode } from 'react'; +import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery'; +import type { Board } from '@/generated/prisma/client'; + +export const BoardContext = createContext(null); + +export function BoardProvider({ boardId, children }: { boardId: string; children: ReactNode }) { + const { data: board, isFetching, isLoading } = useBoardQuery(boardId); + + if (isFetching && isLoading) { + return ; + } + + if (!board) { + return null; + } + + return {children}; +} diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx new file mode 100644 index 000000000..1728a08db --- /dev/null +++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx @@ -0,0 +1,3 @@ +export function BoardBody() { + return

i am bored.

; +} diff --git a/src/app/(main)/boards/[boardId]/BoardHeader.tsx b/src/app/(main)/boards/[boardId]/BoardHeader.tsx index 61461f447..86bd822c2 100644 --- a/src/app/(main)/boards/[boardId]/BoardHeader.tsx +++ b/src/app/(main)/boards/[boardId]/BoardHeader.tsx @@ -1,11 +1,11 @@ -import { Button, Column, Grid, InlineEditField, Row } from '@umami/react-zen'; +import { Button, Column, Grid, Heading, Row, TextField } from '@umami/react-zen'; import { useMessages } from '@/components/hooks'; export function BoardHeader() { const { formatMessage, labels } = useMessages(); const defaultName = formatMessage(labels.untitled); - const name = 'My Board'; - const description = 'This is my board'; + const name = ''; + const description = ''; const handleNameChange = (name: string) => { //updateReport({ name: name || defaultName }); @@ -15,29 +15,50 @@ export function BoardHeader() { //updateReport({ description }); }; + return

asdgfviybiyu8oaero8g9873qrgb875qh0g8

; + return ( - + + asdfasdfds - + onChange={handleNameChange} + autoComplete="off" + style={{ fontSize: '2rem', fontWeight: 700, width: '100%' }} + > + {name} + - + autoComplete="off" + onChange={handleDescriptionChange} + style={{ width: '100%' }} + > + {description} + - + - + ); } diff --git a/src/app/(main)/boards/[boardId]/BoardPage.tsx b/src/app/(main)/boards/[boardId]/BoardPage.tsx index ad6a9d302..858866c16 100644 --- a/src/app/(main)/boards/[boardId]/BoardPage.tsx +++ b/src/app/(main)/boards/[boardId]/BoardPage.tsx @@ -1,17 +1,17 @@ 'use client'; import { Column } from '@umami/react-zen'; import { BoardHeader } from '@/app/(main)/boards/[boardId]/BoardHeader'; +import { BoardProvider } from '@/app/(main)/boards/BoardProvider'; import { PageBody } from '@/components/common/PageBody'; -import { useMessages } from '@/components/hooks'; - -export function BoardPage() { - const { formatMessage, labels } = useMessages(); +export function BoardPage({ boardId }: { boardId: string }) { return ( - - - - - + + + + + + + ); } diff --git a/src/components/boards/Board.tsx b/src/components/boards/Board.tsx deleted file mode 100644 index 70f0fa012..000000000 --- a/src/components/boards/Board.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Column } from '@umami/react-zen'; - -export interface BoardProps { - children?: React.ReactNode; -} - -export function Board({ children }: BoardProps) { - return {children}; -} diff --git a/src/components/hooks/context/useBoard.ts b/src/components/hooks/context/useBoard.ts new file mode 100644 index 000000000..0281dd8d3 --- /dev/null +++ b/src/components/hooks/context/useBoard.ts @@ -0,0 +1,6 @@ +import { useContext } from 'react'; +import { BoardContext } from '@/app/(main)/boards/BoardProvider'; + +export function useBoard() { + return useContext(BoardContext); +} diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index f50890c51..d40fbc3e9 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -1,6 +1,7 @@ 'use client'; // Context hooks +export * from './context/useBoard'; export * from './context/useLink'; export * from './context/usePixel'; export * from './context/useTeam'; @@ -9,6 +10,7 @@ export * from './context/useWebsite'; // Query hooks export * from './queries/useActiveUsersQuery'; +export * from './queries/useBoardQuery'; export * from './queries/useBoardsQuery'; export * from './queries/useDateRangeQuery'; export * from './queries/useDeleteQuery'; diff --git a/src/components/hooks/queries/useBoardQuery.ts b/src/components/hooks/queries/useBoardQuery.ts new file mode 100644 index 000000000..83ca3038e --- /dev/null +++ b/src/components/hooks/queries/useBoardQuery.ts @@ -0,0 +1,17 @@ +import { keepPreviousData } from '@tanstack/react-query'; +import type { ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useModified } from '../useModified'; + +export function useBoardQuery(boardId: string, options?: ReactQueryOptions) { + const { get, useQuery } = useApi(); + const { modified } = useModified(`board:${boardId}`); + + return useQuery({ + queryKey: ['boards', { boardId, modified }], + queryFn: () => get(`/boards/${boardId}`), + enabled: !!boardId && boardId !== 'create', + placeholderData: keepPreviousData, + ...options, + }); +} From 59a16e719be8663ece8dff55894d40c4cf37cabc Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 9 Dec 2025 10:35:10 -0800 Subject: [PATCH 009/412] update bug template --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 2404918b8..d48567e68 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -24,13 +24,13 @@ body: render: shell - type: input attributes: - label: Which Umami version are you using? (if relevant) + label: Which Umami version are you using? description: 'For example: 2.18.0, 2.15.1, 1.39.0, etc' - type: input attributes: - label: Which browser are you using? (if relevant) - description: 'For example: Chrome, Edge, Firefox, etc' + label: How are you deploying your application? + description: 'For example: Vercel, Railway, Docker, etc' - type: input attributes: - label: How are you deploying your application? (if relevant) - description: 'For example: Vercel, Railway, Docker, etc' + label: Which browser are you using? + description: 'For example: Chrome, Edge, Firefox, etc' From 8cc571f548d2a28b50d86bd7540a555c1f8a5e92 Mon Sep 17 00:00:00 2001 From: GochoMugo Date: Thu, 11 Dec 2025 08:53:13 +0300 Subject: [PATCH 010/412] fix: handle denied storage access --- src/tracker/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tracker/index.js b/src/tracker/index.js index ad3648aca..85d274301 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -12,7 +12,13 @@ if (!currentScript) return; const { hostname, href, origin } = location; - const localStorage = href.startsWith('data:') ? undefined : window.localStorage; + + let localStorage; + try { + localStorage = href.startsWith('data:') ? undefined : window.localStorage; + } catch { + /* (DOMException) SecurityError: Access is denied for this document. */ + } const _data = 'data-'; const _false = 'false'; From b088a2ee6edb05ee5ccf103c2b2a2fe2a7721049 Mon Sep 17 00:00:00 2001 From: Kristofor Carle Date: Thu, 11 Dec 2025 14:53:08 -0500 Subject: [PATCH 011/412] fix prisma session race condition error --- src/queries/sql/sessions/saveSessionData.ts | 36 ++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/queries/sql/sessions/saveSessionData.ts b/src/queries/sql/sessions/saveSessionData.ts index 740931777..cce6cd28c 100644 --- a/src/queries/sql/sessions/saveSessionData.ts +++ b/src/queries/sql/sessions/saveSessionData.ts @@ -46,31 +46,23 @@ export async function relationalQuery({ createdAt, })); - const existing = await client.sessionData.findMany({ - where: { - sessionId, - }, - select: { - id: true, - sessionId: true, - dataKey: true, - }, - }); - for (const data of flattenedData) { const { sessionId, dataKey, ...props } = data; - const record = existing.find(e => e.sessionId === sessionId && e.dataKey === dataKey); - if (record) { - await client.sessionData.update({ - where: { - id: record.id, - }, - data: { - ...props, - }, - }); - } else { + // Try to update existing record using compound where clause + // This is safer than using id from a previous query due to race conditions + const updateResult = await client.sessionData.updateMany({ + where: { + sessionId, + dataKey, + }, + data: { + ...props, + }, + }); + + // If no record was updated, create a new one + if (updateResult.count === 0) { await client.sessionData.create({ data, }); From 5b97fb908aa867e0320a506923b334f47bdb6608 Mon Sep 17 00:00:00 2001 From: Egor Fedorov Date: Thu, 11 Dec 2025 23:24:01 +0300 Subject: [PATCH 012/412] fix(events): use correct key for event values --- src/components/hooks/queries/useEventDataValuesQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/hooks/queries/useEventDataValuesQuery.ts b/src/components/hooks/queries/useEventDataValuesQuery.ts index 6529e1426..db2a2d7e0 100644 --- a/src/components/hooks/queries/useEventDataValuesQuery.ts +++ b/src/components/hooks/queries/useEventDataValuesQuery.ts @@ -16,7 +16,7 @@ export function useEventDataValuesQuery( return useQuery({ queryKey: [ 'websites:event-data:values', - { websiteId, event, propertyName, startAt, endAt, unit, timezone, ...filters }, + { websiteId, startAt, endAt, unit, timezone, ...filters, event, propertyName }, ], queryFn: () => get(`/websites/${websiteId}/event-data/values`, { From 5fbef149d04991e4686c95e2ffd9491be54e4d8e Mon Sep 17 00:00:00 2001 From: RaenonX Date: Wed, 10 Dec 2025 13:16:54 +0800 Subject: [PATCH 013/412] Added custom slug for links --- src/app/(main)/links/LinkEditForm.tsx | 65 +++++++++++++-------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/src/app/(main)/links/LinkEditForm.tsx b/src/app/(main)/links/LinkEditForm.tsx index 6c10c7f0a..e9ad18f4f 100644 --- a/src/app/(main)/links/LinkEditForm.tsx +++ b/src/app/(main)/links/LinkEditForm.tsx @@ -4,13 +4,14 @@ import { Form, FormField, FormSubmitButton, + Grid, Icon, Label, Loading, Row, TextField, } from '@umami/react-zen'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useConfig, useLinkQuery, useMessages } from '@/components/hooks'; import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; import { RefreshCw } from '@/components/icons'; @@ -42,7 +43,7 @@ export function LinkEditForm({ const { linksUrl } = useConfig(); const hostUrl = linksUrl || LINKS_URL; const { data, isLoading } = useLinkQuery(linkId); - const [slug, setSlug] = useState(generateId()); + const [defaultSlug] = useState(generateId()); const handleSubmit = async (data: any) => { await mutateAsync(data, { @@ -55,14 +56,6 @@ export function LinkEditForm({ }); }; - const handleSlug = () => { - const slug = generateId(); - - setSlug(slug); - - return slug; - }; - const checkUrl = (url: string) => { if (!isValidUrl(url)) { return formatMessage(labels.invalidUrl); @@ -70,19 +63,19 @@ export function LinkEditForm({ return true; }; - useEffect(() => { - if (data) { - setSlug(data.slug); - } - }, [data]); - if (linkId && isLoading) { return ; } return ( - - {({ setValue }) => { + + {({ setValue, watch }) => { + const slug = watch('slug'); + return ( <> - - - + + + + + + @@ -121,14 +124,6 @@ export function LinkEditForm({ allowCopy style={{ width: '100%' }} /> - From 53dfc5e76ad2e3fe8fc103b62a96cdda38ad9aef Mon Sep 17 00:00:00 2001 From: RaenonX Date: Wed, 10 Dec 2025 13:18:11 +0800 Subject: [PATCH 014/412] Added `pm2.yml` in `.gitignore` --- .gitignore | 91 +++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 753389d1a..de893d0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,45 +1,46 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -node_modules -.pnp -.pnp.js -.pnpm-store -package-lock.json - -# testing -/coverage - -# next.js -/.next -/out - -# production -/build -/public/script.js -/geo -/dist -/generated -/src/generated - -# misc -.DS_Store -.idea -.yarn -*.iml -*.log -.vscode -.tool-versions - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env -.env.* -*.env.* - -*.dev.yml - +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js +.pnpm-store +package-lock.json + +# testing +/coverage + +# next.js +/.next +/out + +# production +/build +/public/script.js +/geo +/dist +/generated +/src/generated +pm2.yml + +# misc +.DS_Store +.idea +.yarn +*.iml +*.log +.vscode +.tool-versions + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.* +*.env.* + +*.dev.yml + From 886544f29752133424acfda2008c2941753f6cf1 Mon Sep 17 00:00:00 2001 From: Jahidul Islam Date: Sat, 13 Dec 2025 16:14:27 +0400 Subject: [PATCH 015/412] Correct UAE emirate names in iso-3166-2.json Updated names of UAE emirates for accuracy. --- public/iso-3166-2.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/iso-3166-2.json b/public/iso-3166-2.json index 347313d72..2b3b5a802 100644 --- a/public/iso-3166-2.json +++ b/public/iso-3166-2.json @@ -6,13 +6,13 @@ "AD-06": "Sant Julia de Loria", "AD-07": "Andorra la Vella", "AD-08": "Escaldes-Engordany", - "AE-AJ": "'Ajman", - "AE-AZ": "Abu Zaby", - "AE-DU": "Dubayy", - "AE-FU": "Al Fujayrah", - "AE-RK": "Ra's al Khaymah", - "AE-SH": "Ash Shariqah", - "AE-UQ": "Umm al Qaywayn", + "AE-AJ": "Ajman", + "AE-AZ": "Abu Dhabi", + "AE-DU": "Dubai", + "AE-FU": "Al Fujairah", + "AE-RK": "Ras al Khaimah", + "AE-SH": "Sharjah", + "AE-UQ": "Umm al Quwain", "AF-BAL": "Balkh", "AF-BAM": "Bamyan", "AF-BDG": "Badghis", From 437c168e6f28318c12c7823bd21e5823f3672449 Mon Sep 17 00:00:00 2001 From: journry789 Date: Mon, 15 Dec 2025 13:56:39 +0800 Subject: [PATCH 016/412] This resolves the issue of being unable to obtain the client's IP address due to the IPv6 format. --- src/lib/ip.ts | 70 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/src/lib/ip.ts b/src/lib/ip.ts index 5cd775746..a0e3a8252 100644 --- a/src/lib/ip.ts +++ b/src/lib/ip.ts @@ -1,3 +1,5 @@ +import ipaddr from 'ipaddr.js'; + export const IP_ADDRESS_HEADERS = [ 'true-client-ip', // CDN 'cf-connecting-ip', // Cloudflare @@ -13,35 +15,87 @@ export const IP_ADDRESS_HEADERS = [ 'x-forwarded', ]; +/** + * Normalize IP strings to a canonical form: + * - strips IPv4-mapped IPv6 (e.g. ::ffff:192.0.2.1 -> 192.0.2.1) + * - keeps valid IPv4/IPv6 as-is (canonically formatted by ipaddr.js) + */ +function normalizeIp(ip?: string | null) { + if (!ip) return ip; + + try { + const parsed = ipaddr.parse(ip); + + if (parsed.kind() === 'ipv6' && (parsed as ipaddr.IPv6).isIPv4MappedAddress()) { + return (parsed as ipaddr.IPv6).toIPv4Address().toString(); + } + + return parsed.toString(); + } catch { + // Fallback: return original if parsing fails + return ip; + } +} + +function resolveIp(ip?: string | null) { + if (!ip) return ip; + + // First, try as-is + const normalized = normalizeIp(ip); + try { + ipaddr.parse(normalized); + return normalized; + } catch { + // try stripping port (handles IPv4:port; leaves IPv6 intact) + const stripped = stripPort(ip); + if (stripped !== ip) { + const normalizedStripped = normalizeIp(stripped); + try { + ipaddr.parse(normalizedStripped); + return normalizedStripped; + } catch { + return normalizedStripped; + } + } + + return normalized; + } +} + export function getIpAddress(headers: Headers) { const customHeader = process.env.CLIENT_IP_HEADER; if (customHeader && headers.get(customHeader)) { - return headers.get(customHeader); + return resolveIp(headers.get(customHeader)); } - const header = IP_ADDRESS_HEADERS.find(name => { - return headers.get(name); - }); + const header = IP_ADDRESS_HEADERS.find(name => headers.get(name)); + if (!header) { + return undefined; + } const ip = headers.get(header); if (header === 'x-forwarded-for') { - return ip?.split(',')?.[0]?.trim(); + return resolveIp(ip?.split(',')?.[0]?.trim()); } if (header === 'forwarded') { const match = ip.match(/for=(\[?[0-9a-fA-F:.]+\]?)/); if (match) { - return match[1]; + return resolveIp(match[1]); } } - return ip; + return resolveIp(ip); } -export function stripPort(ip: string) { +export function stripPort(ip?: string | null) { + if (!ip) { + return ip; + } + if (ip.startsWith('[')) { const endBracket = ip.indexOf(']'); if (endBracket !== -1) { From d04fff65fe07875af5d2866762e3963c99e30ca3 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 17 Dec 2025 09:34:59 -0800 Subject: [PATCH 017/412] fix monthly truncation timezone issue --- src/lib/clickhouse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index f2ebbb722..0a336f804 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -61,7 +61,7 @@ function getDateStringSQL(data: any, unit: string = 'utc', timezone?: string) { function getDateSQL(field: string, unit: string, timezone?: string) { if (timezone) { - return `toDateTime(date_trunc('${unit}', ${field}, '${timezone}'))`; + return `toDateTime(date_trunc('${unit}', ${field}, '${timezone}'), '${timezone}')`; } return `toDateTime(date_trunc('${unit}', ${field}))`; } From 37b6194c5f6dae2f3662cc2f494b07a5ae3a6584 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 17 Dec 2025 13:28:34 -0800 Subject: [PATCH 018/412] set 6 month retention for hobby users --- src/lib/load.ts | 12 ++++++++++++ src/lib/request.ts | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/lib/load.ts b/src/lib/load.ts index d4d6c3c75..d143344a5 100644 --- a/src/lib/load.ts +++ b/src/lib/load.ts @@ -38,3 +38,15 @@ export async function fetchSession(websiteId: string, sessionId: string): Promis return session; } + +export async function fetchAccount(websiteId: string) { + let account = null; + + const cache = await redis.client.get(`cache:website:${websiteId}`); + + if (cache) { + account = await redis.client.get(`account:${cache.account_id}`); + } + + return account; +} diff --git a/src/lib/request.ts b/src/lib/request.ts index 42c449048..f5b984810 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -1,8 +1,9 @@ +import { startOfMonth, subMonths } from 'date-fns'; import { z } from 'zod'; import { checkAuth } from '@/lib/auth'; import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS } from '@/lib/constants'; import { getAllowedUnits, getMinimumUnit, maxDate, parseDateRange } from '@/lib/date'; -import { fetchWebsite } from '@/lib/load'; +import { fetchAccount, fetchWebsite } from '@/lib/load'; import { filtersArrayToObject } from '@/lib/params'; import { badRequest, unauthorized } from '@/lib/response'; import type { QueryFilters } from '@/lib/types'; @@ -82,6 +83,15 @@ export function getRequestFilters(query: Record) { export async function setWebsiteDate(websiteId: string, data: Record) { const website = await fetchWebsite(websiteId); + const cloudMode = !!process.env.CLOUD_MODE; + + if (cloudMode) { + const account = await fetchAccount(websiteId); + + if (!account?.hasSubscription) { + data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6))); + } + } if (website?.resetAt) { data.startDate = maxDate(data.startDate, new Date(website?.resetAt)); From 741c6039e60020e62dd81c20f3f01e365d7d2b73 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 18 Dec 2025 10:35:52 -0800 Subject: [PATCH 019/412] refactor 6 month retention. use auth instead of cache:website --- src/app/api/reports/attribution/route.ts | 4 ++-- src/app/api/reports/breakdown/route.ts | 4 ++-- src/app/api/reports/funnel/route.ts | 4 ++-- src/app/api/reports/goal/route.ts | 4 ++-- src/app/api/reports/retention/route.ts | 4 ++-- src/app/api/reports/revenue/route.ts | 4 ++-- src/app/api/reports/utm/route.ts | 4 ++-- .../websites/[websiteId]/event-data/events/route.ts | 2 +- .../websites/[websiteId]/event-data/fields/route.ts | 2 +- .../[websiteId]/event-data/properties/route.ts | 2 +- .../websites/[websiteId]/event-data/stats/route.ts | 2 +- .../websites/[websiteId]/event-data/values/route.ts | 2 +- src/app/api/websites/[websiteId]/events/route.ts | 2 +- .../api/websites/[websiteId]/events/series/route.ts | 2 +- src/app/api/websites/[websiteId]/export/route.ts | 2 +- .../websites/[websiteId]/metrics/expanded/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/route.ts | 2 +- src/app/api/websites/[websiteId]/pageviews/route.ts | 2 +- .../[websiteId]/session-data/properties/route.ts | 2 +- .../websites/[websiteId]/session-data/values/route.ts | 2 +- .../sessions/[sessionId]/activity/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/route.ts | 2 +- .../api/websites/[websiteId]/sessions/stats/route.ts | 2 +- .../api/websites/[websiteId]/sessions/weekly/route.ts | 2 +- src/app/api/websites/[websiteId]/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/values/route.ts | 2 +- src/app/api/websites/route.ts | 4 ++-- src/lib/load.ts | 10 ++-------- src/lib/request.ts | 11 ++++++----- 29 files changed, 43 insertions(+), 48 deletions(-) diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index bd7d86dc7..c487120f1 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); const data = await getAttribution(websiteId, parameters as AttributionParameters, filters); diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index 3c5931458..4464afaaa 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters); diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index c13f6f1c8..0d1fbf593 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); const data = await getFunnel(websiteId, parameters as FunnelParameters, filters); diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index 3bd0415d6..4f376bd1d 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); const data = await getGoal(websiteId, parameters as GoalParameters, filters); diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index d1a7d698b..33e226619 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId); - const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); const data = await getRetention(websiteId, parameters as RetentionParameters, filters); diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index 6a556612b..1d3d54bf6 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); const data = await getRevenue(websiteId, parameters as RevenuParameters, filters); diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index 577fdab79..6c6ff9065 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -18,8 +18,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId); - const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); const data = { utm_source: [], diff --git a/src/app/api/websites/[websiteId]/event-data/events/route.ts b/src/app/api/websites/[websiteId]/event-data/events/route.ts index eb6ee6ed8..dec689967 100644 --- a/src/app/api/websites/[websiteId]/event-data/events/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/events/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventDataEvents(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/event-data/fields/route.ts b/src/app/api/websites/[websiteId]/event-data/fields/route.ts index bce6a977c..b6b3bd787 100644 --- a/src/app/api/websites/[websiteId]/event-data/fields/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/fields/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventDataFields(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/properties/route.ts b/src/app/api/websites/[websiteId]/event-data/properties/route.ts index 52d15cfbd..ad4be6612 100644 --- a/src/app/api/websites/[websiteId]/event-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/stats/route.ts b/src/app/api/websites/[websiteId]/event-data/stats/route.ts index 042e989a4..141f0531b 100644 --- a/src/app/api/websites/[websiteId]/event-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventDataStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/values/route.ts b/src/app/api/websites/[websiteId]/event-data/values/route.ts index 12e8f2dc0..10f8847b0 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -30,7 +30,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/events/route.ts b/src/app/api/websites/[websiteId]/events/route.ts index 74ec3ece4..69dcaf057 100644 --- a/src/app/api/websites/[websiteId]/events/route.ts +++ b/src/app/api/websites/[websiteId]/events/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getWebsiteEvents(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/events/series/route.ts b/src/app/api/websites/[websiteId]/events/series/route.ts index 977e9c813..8df3d36c1 100644 --- a/src/app/api/websites/[websiteId]/events/series/route.ts +++ b/src/app/api/websites/[websiteId]/events/series/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getEventStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/export/route.ts b/src/app/api/websites/[websiteId]/export/route.ts index eec81c6d4..9e20cd009 100644 --- a/src/app/api/websites/[websiteId]/export/route.ts +++ b/src/app/api/websites/[websiteId]/export/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([ getEventMetrics(websiteId, { type: 'event' }, filters), diff --git a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts index d52c17736..bb84bf139 100644 --- a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/metrics/route.ts b/src/app/api/websites/[websiteId]/metrics/route.ts index 12784adbe..2b1487f21 100644 --- a/src/app/api/websites/[websiteId]/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/pageviews/route.ts b/src/app/api/websites/[websiteId]/pageviews/route.ts index af59bce46..628d53358 100644 --- a/src/app/api/websites/[websiteId]/pageviews/route.ts +++ b/src/app/api/websites/[websiteId]/pageviews/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const [pageviews, sessions] = await Promise.all([ getPageviewStats(websiteId, filters), diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index 2d8db1535..227700d23 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getSessionDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index 7d06870ac..4c1f3f251 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -29,7 +29,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getSessionDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts index 41b766d03..40ad362cb 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts @@ -25,7 +25,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getSessionActivity(websiteId, sessionId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/route.ts b/src/app/api/websites/[websiteId]/sessions/route.ts index ed4757a1c..e0d00cf59 100644 --- a/src/app/api/websites/[websiteId]/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getWebsiteSessions(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/stats/route.ts b/src/app/api/websites/[websiteId]/sessions/stats/route.ts index 459830edf..7393b5804 100644 --- a/src/app/api/websites/[websiteId]/sessions/stats/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const metrics = await getWebsiteSessionStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index b9ccf3ef0..075ddea59 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getWeeklyTraffic(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 07c8b9699..f307325a6 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); const data = await getWebsiteStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/values/route.ts b/src/app/api/websites/[websiteId]/values/route.ts index 172325e3f..7b8bd58e3 100644 --- a/src/app/api/websites/[websiteId]/values/route.ts +++ b/src/app/api/websites/[websiteId]/values/route.ts @@ -42,7 +42,7 @@ export async function GET( value: segment.name, })); } else { - const filters = await getQueryFilters(query, websiteId); + const filters = await getQueryFilters(query, websiteId, auth.user.id); values = await getValues(websiteId, FILTER_COLUMNS[type], filters); } diff --git a/src/app/api/websites/route.ts b/src/app/api/websites/route.ts index e2b26c108..dd8e0ffdd 100644 --- a/src/app/api/websites/route.ts +++ b/src/app/api/websites/route.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; import { uuid } from '@/lib/crypto'; -import redis from '@/lib/redis'; +import { fetchAccount } from '@/lib/load'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, searchParams } from '@/lib/schema'; @@ -52,7 +52,7 @@ export async function POST(request: Request) { const { id, name, domain, shareId, teamId } = body; if (process.env.CLOUD_MODE && !teamId) { - const account = await redis.client.get(`account:${auth.user.id}`); + const account = await fetchAccount(auth.user.id); if (!account?.hasSubscription) { const count = await getWebsiteCount(auth.user.id); diff --git a/src/lib/load.ts b/src/lib/load.ts index d143344a5..bf527975f 100644 --- a/src/lib/load.ts +++ b/src/lib/load.ts @@ -39,14 +39,8 @@ export async function fetchSession(websiteId: string, sessionId: string): Promis return session; } -export async function fetchAccount(websiteId: string) { - let account = null; - - const cache = await redis.client.get(`cache:website:${websiteId}`); - - if (cache) { - account = await redis.client.get(`account:${cache.account_id}`); - } +export async function fetchAccount(userId: string) { + const account = await redis.client.get(`account:${userId}`); return account; } diff --git a/src/lib/request.ts b/src/lib/request.ts index f5b984810..e6450bf31 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -17,7 +17,7 @@ export async function parseRequest( const url = new URL(request.url); let query = Object.fromEntries(url.searchParams); let body = await getJsonBody(request); - let error: () => undefined | undefined; + let error: () => undefined | undefined | Response; let auth = null; if (schema) { @@ -81,12 +81,12 @@ export function getRequestFilters(query: Record) { return result; } -export async function setWebsiteDate(websiteId: string, data: Record) { +export async function setWebsiteDate(websiteId: string, userId: string, data: Record) { const website = await fetchWebsite(websiteId); const cloudMode = !!process.env.CLOUD_MODE; - if (cloudMode) { - const account = await fetchAccount(websiteId); + if (cloudMode && !website.teamId) { + const account = await fetchAccount(userId); if (!account?.hasSubscription) { data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6))); @@ -103,12 +103,13 @@ export async function setWebsiteDate(websiteId: string, data: Record, websiteId?: string, + userId?: string, ): Promise { const dateRange = getRequestDateRange(params); const filters = getRequestFilters(params); if (websiteId) { - await setWebsiteDate(websiteId, dateRange); + await setWebsiteDate(websiteId, userId, dateRange); if (params.segment) { const segmentParams = (await getWebsiteSegment(websiteId, params.segment)) From 86d2672c47fe74f38ff71a62e8540c1bc5ffb7d1 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 18 Dec 2025 11:33:29 -0800 Subject: [PATCH 020/412] fix shareId error --- src/app/api/reports/attribution/route.ts | 2 +- src/app/api/reports/breakdown/route.ts | 2 +- src/app/api/reports/funnel/route.ts | 2 +- src/app/api/reports/goal/route.ts | 2 +- src/app/api/reports/retention/route.ts | 2 +- src/app/api/reports/revenue/route.ts | 2 +- src/app/api/reports/utm/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/events/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/fields/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/properties/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/values/route.ts | 2 +- src/app/api/websites/[websiteId]/events/route.ts | 2 +- src/app/api/websites/[websiteId]/events/series/route.ts | 2 +- src/app/api/websites/[websiteId]/export/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/expanded/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/route.ts | 2 +- src/app/api/websites/[websiteId]/pageviews/route.ts | 2 +- .../api/websites/[websiteId]/session-data/properties/route.ts | 2 +- src/app/api/websites/[websiteId]/session-data/values/route.ts | 2 +- .../websites/[websiteId]/sessions/[sessionId]/activity/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/weekly/route.ts | 2 +- src/app/api/websites/[websiteId]/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/values/route.ts | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index c487120f1..ab9b1ddbc 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { } const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const data = await getAttribution(websiteId, parameters as AttributionParameters, filters); diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index 4464afaaa..a06636c74 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { } const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters); diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index 0d1fbf593..f6e210293 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { } const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const data = await getFunnel(websiteId, parameters as FunnelParameters, filters); diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index 4f376bd1d..db2aabcef 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { } const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const data = await getGoal(websiteId, parameters as GoalParameters, filters); diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index 33e226619..5adf7bb85 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -17,7 +17,7 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); const data = await getRetention(websiteId, parameters as RetentionParameters, filters); diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index 1d3d54bf6..f4146b966 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { } const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const data = await getRevenue(websiteId, parameters as RevenuParameters, filters); diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index 6c6ff9065..d4af4da06 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -18,7 +18,7 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user.id); + const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); const data = { diff --git a/src/app/api/websites/[websiteId]/event-data/events/route.ts b/src/app/api/websites/[websiteId]/event-data/events/route.ts index dec689967..444afa273 100644 --- a/src/app/api/websites/[websiteId]/event-data/events/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/events/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventDataEvents(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/event-data/fields/route.ts b/src/app/api/websites/[websiteId]/event-data/fields/route.ts index b6b3bd787..e034d9375 100644 --- a/src/app/api/websites/[websiteId]/event-data/fields/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/fields/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventDataFields(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/properties/route.ts b/src/app/api/websites/[websiteId]/event-data/properties/route.ts index ad4be6612..29719fb22 100644 --- a/src/app/api/websites/[websiteId]/event-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/stats/route.ts b/src/app/api/websites/[websiteId]/event-data/stats/route.ts index 141f0531b..1d1e76dff 100644 --- a/src/app/api/websites/[websiteId]/event-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventDataStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/values/route.ts b/src/app/api/websites/[websiteId]/event-data/values/route.ts index 10f8847b0..ed01fb2b6 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -30,7 +30,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/events/route.ts b/src/app/api/websites/[websiteId]/events/route.ts index 69dcaf057..dfabb87fb 100644 --- a/src/app/api/websites/[websiteId]/events/route.ts +++ b/src/app/api/websites/[websiteId]/events/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getWebsiteEvents(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/events/series/route.ts b/src/app/api/websites/[websiteId]/events/series/route.ts index 8df3d36c1..d5b925590 100644 --- a/src/app/api/websites/[websiteId]/events/series/route.ts +++ b/src/app/api/websites/[websiteId]/events/series/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getEventStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/export/route.ts b/src/app/api/websites/[websiteId]/export/route.ts index 9e20cd009..f9749f34e 100644 --- a/src/app/api/websites/[websiteId]/export/route.ts +++ b/src/app/api/websites/[websiteId]/export/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([ getEventMetrics(websiteId, { type: 'event' }, filters), diff --git a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts index bb84bf139..7e6fbbfdf 100644 --- a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/metrics/route.ts b/src/app/api/websites/[websiteId]/metrics/route.ts index 2b1487f21..2d0e6a600 100644 --- a/src/app/api/websites/[websiteId]/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/pageviews/route.ts b/src/app/api/websites/[websiteId]/pageviews/route.ts index 628d53358..dc921bc0c 100644 --- a/src/app/api/websites/[websiteId]/pageviews/route.ts +++ b/src/app/api/websites/[websiteId]/pageviews/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const [pageviews, sessions] = await Promise.all([ getPageviewStats(websiteId, filters), diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index 227700d23..a0aed73ce 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getSessionDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index 4c1f3f251..db7106548 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -29,7 +29,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getSessionDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts index 40ad362cb..3e70bea0a 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts @@ -25,7 +25,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getSessionActivity(websiteId, sessionId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/route.ts b/src/app/api/websites/[websiteId]/sessions/route.ts index e0d00cf59..f344476c3 100644 --- a/src/app/api/websites/[websiteId]/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getWebsiteSessions(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/stats/route.ts b/src/app/api/websites/[websiteId]/sessions/stats/route.ts index 7393b5804..74b4e5e80 100644 --- a/src/app/api/websites/[websiteId]/sessions/stats/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const metrics = await getWebsiteSessionStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index 075ddea59..f6dfd206b 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getWeeklyTraffic(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index f307325a6..2bf862cdc 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); const data = await getWebsiteStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/values/route.ts b/src/app/api/websites/[websiteId]/values/route.ts index 7b8bd58e3..c2c95b375 100644 --- a/src/app/api/websites/[websiteId]/values/route.ts +++ b/src/app/api/websites/[websiteId]/values/route.ts @@ -42,7 +42,7 @@ export async function GET( value: segment.name, })); } else { - const filters = await getQueryFilters(query, websiteId, auth.user.id); + const filters = await getQueryFilters(query, websiteId, auth.user?.id); values = await getValues(websiteId, FILTER_COLUMNS[type], filters); } From 3072f02f1bc2a5fad3347a0389706ea087029aeb Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 19 Dec 2025 13:32:20 -0800 Subject: [PATCH 021/412] =?UTF-8?q?Add=20table=20alias=20to=20filterQuery.?= =?UTF-8?q?=20Closed=20=C2=A0#3869?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/prisma.ts | 14 ++++++++++---- src/queries/sql/reports/getRevenue.ts | 7 ++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index 64cb870fd..bfd007d1b 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -74,15 +74,21 @@ function getSearchSQL(column: string, param: string = 'search'): string { function mapFilter(column: string, operator: string, name: string, type: string = '') { const value = `{{${name}${type ? `::${type}` : ''}}}`; + if (name.startsWith('cohort_')) { + name = name.slice('cohort_'.length); + } + + const table = SESSION_COLUMNS.includes(name) ? 'session' : 'website_event'; + switch (operator) { case OPERATORS.equals: - return `${column} = ${value}`; + return `${table}.${column} = ${value}`; case OPERATORS.notEquals: - return `${column} != ${value}`; + return `${table}.${column} != ${value}`; case OPERATORS.contains: - return `${column} ilike ${value}`; + return `${table}.${column} ilike ${value}`; case OPERATORS.doesNotContain: - return `${column} not ilike ${value}`; + return `${table}.${column} not ilike ${value}`; default: return ''; } diff --git a/src/queries/sql/reports/getRevenue.ts b/src/queries/sql/reports/getRevenue.ts index 19b75d429..2a4604fec 100644 --- a/src/queries/sql/reports/getRevenue.ts +++ b/src/queries/sql/reports/getRevenue.ts @@ -41,14 +41,15 @@ async function relationalQuery( currency, }); - const joinQuery = filterQuery - ? `join website_event + const joinQuery = + filterQuery || cohortQuery + ? `join website_event on website_event.website_id = revenue.website_id and website_event.session_id = revenue.session_id and website_event.event_id = revenue.event_id and website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}}` - : ''; + : ''; const chart = await rawQuery( ` From 912d2d544dac632cf08064a08deb46ac9a07bcd4 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 19 Dec 2025 14:21:42 -0800 Subject: [PATCH 022/412] Fix deleted website visibility bug Closes #3865 --- src/app/(main)/links/[linkId]/page.tsx | 6 ++++++ src/app/(main)/pixels/[pixelId]/page.tsx | 6 ++++++ src/app/(main)/websites/[websiteId]/layout.tsx | 6 ++++++ src/lib/request.ts | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/app/(main)/links/[linkId]/page.tsx b/src/app/(main)/links/[linkId]/page.tsx index 4317ada23..3a5f5d7ee 100644 --- a/src/app/(main)/links/[linkId]/page.tsx +++ b/src/app/(main)/links/[linkId]/page.tsx @@ -1,8 +1,14 @@ import type { Metadata } from 'next'; +import { getLink } from '@/queries/prisma'; import { LinkPage } from './LinkPage'; export default async function ({ params }: { params: Promise<{ linkId: string }> }) { const { linkId } = await params; + const link = await getLink(linkId); + + if (!link || link?.deletedAt) { + return null; + } return ; } diff --git a/src/app/(main)/pixels/[pixelId]/page.tsx b/src/app/(main)/pixels/[pixelId]/page.tsx index d1db92f3d..e174c195c 100644 --- a/src/app/(main)/pixels/[pixelId]/page.tsx +++ b/src/app/(main)/pixels/[pixelId]/page.tsx @@ -1,8 +1,14 @@ import type { Metadata } from 'next'; +import { getPixel } from '@/queries/prisma'; import { PixelPage } from './PixelPage'; export default async function ({ params }: { params: { pixelId: string } }) { const { pixelId } = await params; + const pixel = await getPixel(pixelId); + + if (!pixel || pixel?.deletedAt) { + return null; + } return ; } diff --git a/src/app/(main)/websites/[websiteId]/layout.tsx b/src/app/(main)/websites/[websiteId]/layout.tsx index 67595e9d1..b12ff9505 100644 --- a/src/app/(main)/websites/[websiteId]/layout.tsx +++ b/src/app/(main)/websites/[websiteId]/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next'; import { WebsiteLayout } from '@/app/(main)/websites/[websiteId]/WebsiteLayout'; +import { getWebsite } from '@/queries/prisma'; export default async function ({ children, @@ -9,6 +10,11 @@ export default async function ({ params: Promise<{ websiteId: string }>; }) { const { websiteId } = await params; + const website = await getWebsite(websiteId); + + if (!website || website?.deletedAt) { + return null; + } return {children}; } diff --git a/src/lib/request.ts b/src/lib/request.ts index e6450bf31..d6543b184 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -85,7 +85,7 @@ export async function setWebsiteDate(websiteId: string, userId: string, data: Re const website = await fetchWebsite(websiteId); const cloudMode = !!process.env.CLOUD_MODE; - if (cloudMode && !website.teamId) { + if (cloudMode && website && !website.teamId) { const account = await fetchAccount(userId); if (!account?.hasSubscription) { From 687318bd0996b7593a7e4fa63544a92146a33188 Mon Sep 17 00:00:00 2001 From: kkhys Date: Sat, 20 Dec 2025 11:58:25 +0900 Subject: [PATCH 023/412] fix Japanese translation for label 'breakdown' --- src/lang/ja-JP.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/ja-JP.json b/src/lang/ja-JP.json index 7d2bf4030..20b48f40f 100644 --- a/src/lang/ja-JP.json +++ b/src/lang/ja-JP.json @@ -23,7 +23,7 @@ "label.behavior": "行動", "label.boards": "ボード", "label.bounce-rate": "直帰率", - "label.breakdown": "故障", + "label.breakdown": "内訳", "label.browser": "ブラウザ", "label.browsers": "ブラウザ", "label.campaigns": "キャンペーン", From ad264f941d056f700e7af40ab1a5d78996379d22 Mon Sep 17 00:00:00 2001 From: Mintihuang <43734212+Mintimate@users.noreply.github.com> Date: Mon, 22 Dec 2025 11:35:28 +0000 Subject: [PATCH 024/412] =?UTF-8?q?feat:=20add=20EdgeOne=20headers=20for?= =?UTF-8?q?=20geolocation=20detection=E2=80=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/detect.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 68cb66726..910d122be 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -28,6 +28,12 @@ const PROVIDER_HEADERS = [ regionHeader: 'cloudfront-viewer-country-region', cityHeader: 'cloudfront-viewer-city', }, + // EdgeOne headers (requires custom request headers in Rule Priorities, see: https://edgeone.ai/document/46151) + { + countryHeader: 'eo-ipcountry', + regionHeader: 'eo-region-code', + cityHeader: 'eo-ipcity', + }, ]; export function getDevice(userAgent: string, screen: string = '') { From b0ed4bddb67ed7989f86694d104079f4ce65ff6e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 22 Dec 2025 10:59:33 -0800 Subject: [PATCH 025/412] change reset/delete website to interactive transaction with timeout Closes #3905 --- src/queries/prisma/website.ts | 93 ++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/queries/prisma/website.ts b/src/queries/prisma/website.ts index 79cb72473..6c8625d06 100644 --- a/src/queries/prisma/website.ts +++ b/src/queries/prisma/website.ts @@ -132,42 +132,46 @@ export async function updateWebsite( } export async function resetWebsite(websiteId: string) { - const { client, transaction } = prisma; + const { transaction } = prisma; const cloudMode = !!process.env.CLOUD_MODE; return transaction( - [ - client.revenue.deleteMany({ + async tx => { + await tx.revenue.deleteMany({ where: { websiteId }, - }), - client.eventData.deleteMany({ + }); + + await tx.eventData.deleteMany({ where: { websiteId }, - }), - client.sessionData.deleteMany({ + }); + + await tx.sessionData.deleteMany({ where: { websiteId }, - }), - client.websiteEvent.deleteMany({ + }); + + await tx.websiteEvent.deleteMany({ where: { websiteId }, - }), - client.session.deleteMany({ + }); + + await tx.session.deleteMany({ where: { websiteId }, - }), - client.website.update({ + }); + + const website = await tx.website.update({ where: { id: websiteId }, data: { resetAt: new Date(), }, - }), - ], + }); + + return website; + }, { timeout: 30000, }, ).then(async data => { if (cloudMode) { - await redis.client.set( - `website:${websiteId}`, - data.find(website => website.id), - ); + await redis.client.set(`website:${websiteId}`, data); } return data; @@ -175,43 +179,52 @@ export async function resetWebsite(websiteId: string) { } export async function deleteWebsite(websiteId: string) { - const { client, transaction } = prisma; + const { transaction } = prisma; const cloudMode = !!process.env.CLOUD_MODE; return transaction( - [ - client.revenue.deleteMany({ + async tx => { + await tx.revenue.deleteMany({ where: { websiteId }, - }), - client.eventData.deleteMany({ + }); + + await tx.eventData.deleteMany({ where: { websiteId }, - }), - client.sessionData.deleteMany({ + }); + + await tx.sessionData.deleteMany({ where: { websiteId }, - }), - client.websiteEvent.deleteMany({ + }); + + await tx.websiteEvent.deleteMany({ where: { websiteId }, - }), - client.session.deleteMany({ + }); + + await tx.session.deleteMany({ where: { websiteId }, - }), - client.report.deleteMany({ + }); + + await tx.report.deleteMany({ where: { websiteId }, - }), - client.segment.deleteMany({ + }); + + await tx.segment.deleteMany({ where: { websiteId }, - }), - cloudMode - ? client.website.update({ + }); + + const website = cloudMode + ? await tx.website.update({ data: { deletedAt: new Date(), }, where: { id: websiteId }, }) - : client.website.delete({ + : await tx.website.delete({ where: { id: websiteId }, - }), - ], + }); + + return website; + }, { timeout: 30000, }, From 6859f00bf643d1a4f58b46cfe8d32e7d673074f3 Mon Sep 17 00:00:00 2001 From: JiPai Date: Tue, 23 Dec 2025 22:39:33 +0800 Subject: [PATCH 026/412] chore(i18n): update zh-CN translation --- public/intl/messages/zh-CN.json | 210 ++++++++++++++++++++++++++++++-- src/lang/zh-CN.json | 49 ++++++-- 2 files changed, 241 insertions(+), 18 deletions(-) diff --git a/public/intl/messages/zh-CN.json b/public/intl/messages/zh-CN.json index b3d2f3c00..1c3f32407 100644 --- a/public/intl/messages/zh-CN.json +++ b/public/intl/messages/zh-CN.json @@ -5,6 +5,18 @@ "value": "访问代码" } ], + "label.account": [ + { + "type": 0, + "value": "账户" + } + ], + "label.action": [ + { + "type": 0, + "value": "行为" + } + ], "label.actions": [ { "type": 0, @@ -35,12 +47,24 @@ "value": "添加描述" } ], + "label.add-link": [ + { + "type": 0, + "value": "添加链接" + } + ], "label.add-member": [ { "type": 0, "value": "添加成员" } ], + "label.add-pixel": [ + { + "type": 0, + "value": "添加像素" + } + ], "label.add-step": [ { "type": 0, @@ -83,12 +107,24 @@ "value": "所有时间段" } ], + "label.analysis": [ + { + "type": 0, + "value": "分析" + } + ], "label.analytics": [ { "type": 0, "value": "分析" } ], + "label.application": [ + { + "type": 0, + "value": "应用" + } + ], "label.apply": [ { "type": 0, @@ -107,6 +143,12 @@ "value": "查看用户如何与您的营销互动,以及是什么促成了转化。" } ], + "label.audience": [ + { + "type": 0, + "value": "受众" + } + ], "label.average": [ { "type": 0, @@ -125,6 +167,12 @@ "value": "之前" } ], + "label.behavior": [ + { + "type": 0, + "value": "行为" + } + ], "label.boards": [ { "type": 0, @@ -173,12 +221,24 @@ "value": "修改密码" } ], + "label.channel": [ + { + "type": 0, + "value": "渠道" + } + ], "label.channels": [ { "type": 0, "value": "渠道" } ], + "label.chart": [ + { + "type": 0, + "value": "图表" + } + ], "label.cities": [ { "type": 0, @@ -203,6 +263,12 @@ "value": "队列" } ], + "label.cohorts": [ + { + "type": 0, + "value": "队列" + } + ], "label.compare": [ { "type": 0, @@ -317,6 +383,12 @@ "value": "创建者" } ], + "label.criteria": [ + { + "type": 0, + "value": "条件" + } + ], "label.currency": [ { "type": 0, @@ -419,6 +491,12 @@ "value": "台式机" } ], + "label.destination-url": [ + { + "type": 0, + "value": "目标URL" + } + ], "label.details": [ { "type": 0, @@ -455,6 +533,12 @@ "value": "唯一ID" } ], + "label.documentation": [ + { + "type": 0, + "value": "文档" + } + ], "label.does-not-contain": [ { "type": 0, @@ -479,6 +563,12 @@ "value": "域名" } ], + "label.download": [ + { + "type": 0, + "value": "下载" + } + ], "label.dropoff": [ { "type": 0, @@ -506,7 +596,7 @@ "label.email": [ { "type": 0, - "value": "Email" + "value": "邮箱" } ], "label.enable-share-url": [ @@ -527,6 +617,12 @@ "value": "入口 URL" } ], + "label.environment": [ + { + "type": 0, + "value": "环境" + } + ], "label.event": [ { "type": 0, @@ -671,6 +767,12 @@ "value": "分组" } ], + "label.growth": [ + { + "type": 0, + "value": "Growth" + } + ], "label.hostname": [ { "type": 0, @@ -701,6 +803,12 @@ "value": "通过使用筛选器和划分时间段来更深入地研究数据。" } ], + "label.invalid-url": [ + { + "type": 0, + "value": "无效URL" + } + ], "label.is": [ { "type": 0, @@ -863,12 +971,24 @@ "value": "少于等于" } ], + "label.link": [ + { + "type": 0, + "value": "链接" + } + ], "label.links": [ { "type": 0, "value": "链接" } ], + "label.location": [ + { + "type": 0, + "value": "位置" + } + ], "label.login": [ { "type": 0, @@ -1020,7 +1140,7 @@ "label.online": [ { "type": 0, - "value": "Online" + "value": "在线" } ], "label.organic-search": [ @@ -1165,6 +1285,12 @@ "value": "路径" } ], + "label.pixel": [ + { + "type": 0, + "value": "像素" + } + ], "label.pixels": [ { "type": 0, @@ -1185,6 +1311,12 @@ "value": " 提供支持" } ], + "label.preferences": [ + { + "type": 0, + "value": "偏好" + } + ], "label.previous": [ { "type": 0, @@ -1209,6 +1341,12 @@ "value": "个人资料" } ], + "label.profiles": [ + { + "type": 0, + "value": "个人资料" + } + ], "label.properties": [ { "type": 0, @@ -1248,7 +1386,7 @@ "label.referral": [ { "type": 0, - "value": "Referral" + "value": "来源" } ], "label.referrer": [ @@ -1371,6 +1509,24 @@ "value": "保存" } ], + "label.save-cohort": [ + { + "type": 0, + "value": "Save as cohort" + } + ], + "label.save-segment": [ + { + "type": 0, + "value": "Save as segment" + } + ], + "label.screen": [ + { + "type": 0, + "value": "屏幕" + } + ], "label.screens": [ { "type": 0, @@ -1383,6 +1539,18 @@ "value": "搜索" } ], + "label.segment": [ + { + "type": 0, + "value": "细分" + } + ], + "label.segments": [ + { + "type": 0, + "value": "细分" + } + ], "label.select": [ { "type": 0, @@ -1485,6 +1653,24 @@ "value": "总和" } ], + "label.support": [ + { + "type": 0, + "value": "支持" + } + ], + "label.switch-account": [ + { + "type": 0, + "value": "切换账户" + } + ], + "label.table": [ + { + "type": 0, + "value": "平板" + } + ], "label.tablet": [ { "type": 0, @@ -1635,6 +1821,12 @@ "value": "跟踪代码" } ], + "label.traffic": [ + { + "type": 0, + "value": "流量" + } + ], "label.transactions": [ { "type": 0, @@ -1846,7 +2038,7 @@ "message.bad-request": [ { "type": 0, - "value": "Bad request" + "value": "请求错误" } ], "message.collected-data": [ @@ -1946,7 +2138,7 @@ "message.forbidden": [ { "type": 0, - "value": "Forbidden" + "value": "禁止访问" } ], "message.go-to-settings": [ @@ -2046,13 +2238,13 @@ "message.not-found": [ { "type": 0, - "value": "Not found" + "value": "未找到" } ], "message.nothing-selected": [ { "type": 0, - "value": "Nothing selected." + "value": "未选择" } ], "message.page-not-found": [ @@ -2090,7 +2282,7 @@ "message.sever-error": [ { "type": 0, - "value": "Server error" + "value": "服务器错误" } ], "message.share-url": [ @@ -2158,7 +2350,7 @@ "message.unauthorized": [ { "type": 0, - "value": "Unauthorized" + "value": "未授权" } ], "message.user-deleted": [ diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index c6f01dd5c..8fc0ea67e 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -1,11 +1,15 @@ { "label.access-code": "访问代码", + "label.account": "账户", + "label.action": "行为", "label.actions": "用户行为", "label.activity": "活动日志", "label.add": "添加", "label.add-board": "添加看板", "label.add-description": "添加描述", + "label.add-link": "添加链接", "label.add-member": "添加成员", + "label.add-pixel": "添加像素", "label.add-step": "添加步骤", "label.add-website": "添加网站", "label.admin": "管理员", @@ -13,10 +17,13 @@ "label.after": "之后", "label.all": "所有", "label.all-time": "所有时间段", + "label.analysis": "分析", "label.analytics": "分析", + "label.application": "应用", "label.apply": "应用", "label.attribution": "归因", "label.attribution-description": "查看用户如何与您的营销互动,以及是什么促成了转化。", + "label.audience": "受众", "label.average": "平均", "label.back": "返回", "label.before": "之前", @@ -29,11 +36,14 @@ "label.campaigns": "活动", "label.cancel": "取消", "label.change-password": "修改密码", + "label.channel": "渠道", "label.channels": "渠道", + "label.chart": "图表", "label.cities": "市/县", "label.city": "市/县", "label.clear-all": "清除全部", "label.cohort": "队列", + "label.cohorts": "队列", "label.compare": "比较", "label.compare-dates": "比较日期", "label.confirm": "确认", @@ -53,6 +63,7 @@ "label.create-user": "创建用户", "label.created": "已创建", "label.created-by": "创建者", + "label.criteria": "条件", "label.currency": "货币", "label.current": "当前", "label.current-password": "当前密码", @@ -70,24 +81,28 @@ "label.delete-website": "删除网站", "label.description": "描述", "label.desktop": "台式机", + "label.destination-url": "目标URL", "label.details": "详细信息", "label.device": "设备", "label.devices": "设备", "label.direct": "直接", "label.dismiss": "关闭", "label.distinct-id": "唯一ID", + "label.documentation": "文档", "label.does-not-contain": "不包含", "label.does-not-include": "不包括", "label.doest-not-exist": "不存在", "label.domain": "域名", + "label.download": "下载", "label.dropoff": "丢弃", "label.edit": "编辑", "label.edit-dashboard": "编辑仪表盘", "label.edit-member": "编辑成员", - "label.email": "Email", + "label.email": "邮箱", "label.enable-share-url": "启用共享链接", "label.end-step": "结束步骤", "label.entry": "入口 URL", + "label.environment": "环境", "label.event": "事件", "label.event-data": "事件数据", "label.event-name": "事件名称", @@ -112,11 +127,13 @@ "label.greater-than": "大于", "label.greater-than-equals": "大于或等于", "label.grouped": "分组", + "label.growth": "Growth", "label.hostname": "主机名", "label.includes": "包括", "label.insight": "洞察", "label.insights": "见解", "label.insights-description": "通过使用筛选器和划分时间段来更深入地研究数据。", + "label.invalid-url": "无效URL", "label.is": "等于", "label.is-false": "否", "label.is-not": "不等于", @@ -140,7 +157,9 @@ "label.leave-team": "离开团队", "label.less-than": "少于", "label.less-than-equals": "少于等于", + "label.link": "链接", "label.links": "链接", + "label.location": "位置", "label.login": "登录", "label.logout": "退出", "label.manage": "管理", @@ -161,7 +180,7 @@ "label.none": "无", "label.number-of-records": "{x} {x, plural, one {record} other {records}}", "label.ok": "好的", - "label.online": "Online", + "label.online": "在线", "label.organic-search": "自然搜索", "label.organic-shopping": "自然购物", "label.organic-social": "自然社交", @@ -183,19 +202,22 @@ "label.password": "密码", "label.path": "路径", "label.paths": "路径", + "label.pixel": "像素", "label.pixels": "像素", "label.powered-by": "由 {name} 提供支持", + "label.preferences": "偏好", "label.previous": "先前", "label.previous-period": "上一时期", "label.previous-year": "上一年", "label.profile": "个人资料", + "label.profiles": "个人资料", "label.properties": "属性", "label.property": "属性", "label.queries": "查询", "label.query": "查询", "label.query-parameters": "查询参数", "label.realtime": "实时", - "label.referral": "Referral", + "label.referral": "来源", "label.referrer": "来源", "label.referrers": "来源域名", "label.refresh": "刷新", @@ -216,8 +238,13 @@ "label.role": "角色", "label.run-query": "查询", "label.save": "保存", + "label.save-cohort": "Save as cohort", + "label.save-segment": "Save as segment", + "label.screen": "屏幕", "label.screens": "屏幕尺寸", "label.search": "搜索", + "label.segment": "细分", + "label.segments": "细分", "label.select": "选择", "label.select-date": "选择日期", "label.select-filter": "选择筛选器", @@ -235,6 +262,9 @@ "label.start-step": "开始步骤", "label.steps": "步骤", "label.sum": "总和", + "label.support": "支持", + "label.switch-account": "切换账户", + "label.table": "平板", "label.tablet": "平板", "label.tag": "标签", "label.tags": "标签", @@ -260,6 +290,7 @@ "label.total": "总数", "label.total-records": "总记录数", "label.tracking-code": "跟踪代码", + "label.traffic": "流量", "label.transactions": "交易", "label.transfer": "转移", "label.transfer-website": "转移网站", @@ -292,7 +323,7 @@ "label.yesterday": "昨天", "message.action-confirmation": "请在下方输入框中输入 {confirmation} 以确认操作。", "message.active-users": "当前在线 {x} 位访客", - "message.bad-request": "Bad request", + "message.bad-request": "请求错误", "message.collected-data": "已收集的数据", "message.confirm-delete": "你确定要删除 {target} 吗?", "message.confirm-leave": "你确定要离开 {target} 吗?", @@ -302,7 +333,7 @@ "message.delete-website-warning": "所有相关数据将会被删除。", "message.error": "发生错误。", "message.event-log": "{url} 上的 {event}", - "message.forbidden": "Forbidden", + "message.forbidden": "禁止访问", "message.go-to-settings": "去设置", "message.incorrect-username-password": "用户名或密码不正确。", "message.invalid-domain": "无效域名", @@ -316,13 +347,13 @@ "message.no-teams": "您尚未创建任何团队。", "message.no-users": "暂无用户。", "message.no-websites-configured": "你还没有设置任何网站。", - "message.not-found": "Not found", - "message.nothing-selected": "Nothing selected.", + "message.not-found": "未找到", + "message.nothing-selected": "未选择", "message.page-not-found": "页面未找到。", "message.reset-website": "如确定要重置该网站,请在下面输入 {confirmation} 以确认。", "message.reset-website-warning": "此网站的所有统计数据将被删除,但您的跟踪代码将保持不变。", "message.saved": "保存成功。", - "message.sever-error": "Server error", + "message.sever-error": "服务器错误", "message.share-url": "这是 {target} 的共享链接。", "message.team-already-member": "你已是该团队的成员。", "message.team-not-found": "未找到团队。", @@ -332,7 +363,7 @@ "message.transfer-user-website-to-team": "选择要转移此网站的团队。", "message.transfer-website": "将网站所有权转移到您的账户或其他团队。", "message.triggered-event": "触发事件", - "message.unauthorized": "Unauthorized", + "message.unauthorized": "未授权", "message.user-deleted": "用户已删除。", "message.viewed-page": "已浏览页面", "message.visitor-log": "来自 {country} 的访客在搭载 {os} 的 {device} 上使用 {browser} 浏览器进行访问。" From 783098fadcfa32cbdb62bcfaf48fbe317ccbe0fc Mon Sep 17 00:00:00 2001 From: JiPai Date: Tue, 23 Dec 2025 23:04:41 +0800 Subject: [PATCH 027/412] chore(i18n): update zh-CN translation --- public/intl/messages/zh-CN.json | 8 ++++---- src/lang/zh-CN.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/public/intl/messages/zh-CN.json b/public/intl/messages/zh-CN.json index 1c3f32407..a4ad51fa5 100644 --- a/public/intl/messages/zh-CN.json +++ b/public/intl/messages/zh-CN.json @@ -770,7 +770,7 @@ "label.growth": [ { "type": 0, - "value": "Growth" + "value": "增长" } ], "label.hostname": [ @@ -1512,13 +1512,13 @@ "label.save-cohort": [ { "type": 0, - "value": "Save as cohort" + "value": "保存为群组" } ], "label.save-segment": [ { "type": 0, - "value": "Save as segment" + "value": "保存为细分" } ], "label.screen": [ @@ -1668,7 +1668,7 @@ "label.table": [ { "type": 0, - "value": "平板" + "value": "表格" } ], "label.tablet": [ diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index 8fc0ea67e..5490df422 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -127,7 +127,7 @@ "label.greater-than": "大于", "label.greater-than-equals": "大于或等于", "label.grouped": "分组", - "label.growth": "Growth", + "label.growth": "增长", "label.hostname": "主机名", "label.includes": "包括", "label.insight": "洞察", @@ -238,8 +238,8 @@ "label.role": "角色", "label.run-query": "查询", "label.save": "保存", - "label.save-cohort": "Save as cohort", - "label.save-segment": "Save as segment", + "label.save-cohort": "保存为群组", + "label.save-segment": "保存为细分", "label.screen": "屏幕", "label.screens": "屏幕尺寸", "label.search": "搜索", @@ -264,7 +264,7 @@ "label.sum": "总和", "label.support": "支持", "label.switch-account": "切换账户", - "label.table": "平板", + "label.table": "表格", "label.tablet": "平板", "label.tag": "标签", "label.tags": "标签", From 612b00179ba407c82494dda57dab540f95c63881 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 25 Dec 2025 00:21:10 +0530 Subject: [PATCH 028/412] feat : Add version settings and API endpoint to display application version --- .../preferences/PreferenceSettings.tsx | 5 +++ .../settings/preferences/VersionSetting.tsx | 31 ++++++++++++++++ src/app/api/version/route.ts | 35 +++++++++++++++++++ src/components/messages.ts | 1 + 4 files changed, 72 insertions(+) create mode 100644 src/app/(main)/settings/preferences/VersionSetting.tsx create mode 100644 src/app/api/version/route.ts diff --git a/src/app/(main)/settings/preferences/PreferenceSettings.tsx b/src/app/(main)/settings/preferences/PreferenceSettings.tsx index a2890ce90..cc2d1b620 100644 --- a/src/app/(main)/settings/preferences/PreferenceSettings.tsx +++ b/src/app/(main)/settings/preferences/PreferenceSettings.tsx @@ -4,6 +4,7 @@ import { DateRangeSetting } from './DateRangeSetting'; import { LanguageSetting } from './LanguageSetting'; import { ThemeSetting } from './ThemeSetting'; import { TimezoneSetting } from './TimezoneSetting'; +import { VersionSetting } from './VersionSetting'; export function PreferenceSettings() { const { user } = useLoginQuery(); @@ -31,6 +32,10 @@ export function PreferenceSettings() { + + + + ); } diff --git a/src/app/(main)/settings/preferences/VersionSetting.tsx b/src/app/(main)/settings/preferences/VersionSetting.tsx new file mode 100644 index 000000000..2cfdbeb73 --- /dev/null +++ b/src/app/(main)/settings/preferences/VersionSetting.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { Text } from '@umami/react-zen'; +import { useEffect, useState } from 'react'; + +export function VersionSetting() { + const [version, setVersion] = useState(''); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchVersion = async () => { + try { + const response = await fetch('/api/version'); + const data = await response.json(); + setVersion(data.version || 'unknown'); + } catch (error) { + setVersion('unknown'); + } finally { + setLoading(false); + } + }; + + fetchVersion(); + }, []); + + if (loading) { + return Loading...; + } + + return {version}; +} diff --git a/src/app/api/version/route.ts b/src/app/api/version/route.ts new file mode 100644 index 000000000..af548f732 --- /dev/null +++ b/src/app/api/version/route.ts @@ -0,0 +1,35 @@ +import { readFile } from 'fs/promises'; +import { join } from 'path'; +import { parseRequest } from '@/lib/request'; +import { json } from '@/lib/response'; + +let cachedVersion: string | null = null; + +async function getVersion(): Promise { + if (cachedVersion) { + return cachedVersion; + } + + try { + const packageJsonPath = join(process.cwd(), 'package.json'); + const data = await readFile(packageJsonPath, 'utf-8'); + const packageJson = JSON.parse(data); + cachedVersion = packageJson.version || 'unknown'; + } catch (error) { + cachedVersion = 'unknown'; + } + + return cachedVersion; +} + +export async function GET(request: Request) { + const { error } = await parseRequest(request, null, { skipAuth: true }); + + if (error) { + return error(); + } + + const version = await getVersion(); + + return json({ version }); +} diff --git a/src/components/messages.ts b/src/components/messages.ts index 0438c06e6..712495d81 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -351,6 +351,7 @@ export const labels = defineMessages({ growth: { id: 'label.growth', defaultMessage: 'Growth' }, account: { id: 'label.account', defaultMessage: 'Account' }, application: { id: 'label.application', defaultMessage: 'Application' }, + version: { id: 'label.version', defaultMessage: 'Version' }, saveSegment: { id: 'label.save-segment', defaultMessage: 'Save as segment' }, saveCohort: { id: 'label.save-cohort', defaultMessage: 'Save as cohort' }, analysis: { id: 'label.analysis', defaultMessage: 'Analysis' }, From 5e3e6b3edda495d80bb1e86ed3ccae949c07a469 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 25 Dec 2025 09:48:09 +0530 Subject: [PATCH 029/412] refactor: Simplify version display by removing API endpoint and using constant --- .../settings/preferences/VersionSetting.tsx | 27 ++------------ src/app/api/version/route.ts | 35 ------------------- 2 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 src/app/api/version/route.ts diff --git a/src/app/(main)/settings/preferences/VersionSetting.tsx b/src/app/(main)/settings/preferences/VersionSetting.tsx index 2cfdbeb73..afca1de6b 100644 --- a/src/app/(main)/settings/preferences/VersionSetting.tsx +++ b/src/app/(main)/settings/preferences/VersionSetting.tsx @@ -1,31 +1,8 @@ 'use client'; import { Text } from '@umami/react-zen'; -import { useEffect, useState } from 'react'; +import { CURRENT_VERSION } from '@/lib/constants'; export function VersionSetting() { - const [version, setVersion] = useState(''); - const [loading, setLoading] = useState(true); - - useEffect(() => { - const fetchVersion = async () => { - try { - const response = await fetch('/api/version'); - const data = await response.json(); - setVersion(data.version || 'unknown'); - } catch (error) { - setVersion('unknown'); - } finally { - setLoading(false); - } - }; - - fetchVersion(); - }, []); - - if (loading) { - return Loading...; - } - - return {version}; + return {CURRENT_VERSION}; } diff --git a/src/app/api/version/route.ts b/src/app/api/version/route.ts deleted file mode 100644 index af548f732..000000000 --- a/src/app/api/version/route.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { readFile } from 'fs/promises'; -import { join } from 'path'; -import { parseRequest } from '@/lib/request'; -import { json } from '@/lib/response'; - -let cachedVersion: string | null = null; - -async function getVersion(): Promise { - if (cachedVersion) { - return cachedVersion; - } - - try { - const packageJsonPath = join(process.cwd(), 'package.json'); - const data = await readFile(packageJsonPath, 'utf-8'); - const packageJson = JSON.parse(data); - cachedVersion = packageJson.version || 'unknown'; - } catch (error) { - cachedVersion = 'unknown'; - } - - return cachedVersion; -} - -export async function GET(request: Request) { - const { error } = await parseRequest(request, null, { skipAuth: true }); - - if (error) { - return error(); - } - - const version = await getVersion(); - - return json({ version }); -} From 4eddac21c754d900c0db71a8f8c3745d0d3cb7db Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 25 Dec 2025 20:41:14 +0530 Subject: [PATCH 030/412] feat: Add default currency support and update currency handling in Revenue component --- next.config.ts | 2 ++ .../[websiteId]/(reports)/revenue/Revenue.tsx | 15 ++++++++++++--- src/lib/constants.ts | 2 ++ src/lib/format.ts | 4 +++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/next.config.ts b/next.config.ts index 99dcca0d8..1a4e2e0ec 100644 --- a/next.config.ts +++ b/next.config.ts @@ -8,6 +8,7 @@ const cloudMode = process.env.CLOUD_MODE || ''; const cloudUrl = process.env.CLOUD_URL || ''; const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT || ''; const corsMaxAge = process.env.CORS_MAX_AGE || ''; +const defaultCurrency = process.env.DEFAULT_CURRENCY || ''; const defaultLocale = process.env.DEFAULT_LOCALE || ''; const forceSSL = process.env.FORCE_SSL || ''; const frameAncestors = process.env.ALLOWED_FRAME_URLS || ''; @@ -170,6 +171,7 @@ export default { cloudMode, cloudUrl, currentVersion: pkg.version, + defaultCurrency, defaultLocale, }, basePath, diff --git a/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx index 0e782a164..faee8b9a4 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx @@ -12,9 +12,10 @@ import { ListTable } from '@/components/metrics/ListTable'; import { MetricCard } from '@/components/metrics/MetricCard'; import { MetricsBar } from '@/components/metrics/MetricsBar'; import { renderDateLabels } from '@/lib/charts'; -import { CHART_COLORS } from '@/lib/constants'; +import { CHART_COLORS, CURRENCY_CONFIG, DEFAULT_CURRENCY } from '@/lib/constants'; import { generateTimeSeries } from '@/lib/date'; import { formatLongCurrency, formatLongNumber } from '@/lib/format'; +import { getItem, setItem } from '@/lib/storage'; export interface RevenueProps { websiteId: string; @@ -24,7 +25,15 @@ export interface RevenueProps { } export function Revenue({ websiteId, startDate, endDate, unit }: RevenueProps) { - const [currency, setCurrency] = useState('USD'); + const [currency, setCurrency] = useState( + getItem(CURRENCY_CONFIG) || process.env.defaultCurrency || DEFAULT_CURRENCY, + ); + + const handleCurrencyChange = (value: string) => { + setCurrency(value); + setItem(CURRENCY_CONFIG, value); + }; + const { formatMessage, labels } = useMessages(); const { locale, dateLocale } = useLocale(); const { countryNames } = useCountryNames(locale); @@ -107,7 +116,7 @@ export function Revenue({ websiteId, startDate, endDate, unit }: RevenueProps) { return ( - + {data && ( diff --git a/src/lib/constants.ts b/src/lib/constants.ts index e5090c3c0..502a3df6f 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -4,6 +4,7 @@ export const LOCALE_CONFIG = 'umami.locale'; export const TIMEZONE_CONFIG = 'umami.timezone'; export const DATE_RANGE_CONFIG = 'umami.date-range'; export const THEME_CONFIG = 'umami.theme'; +export const CURRENCY_CONFIG = 'umami.currency'; export const DASHBOARD_CONFIG = 'umami.dashboard'; export const LAST_TEAM_CONFIG = 'umami.last-team'; export const VERSION_CHECK = 'umami.version-check'; @@ -25,6 +26,7 @@ export const DEFAULT_WEBSITE_LIMIT = 10; export const DEFAULT_RESET_DATE = '2000-01-01'; export const DEFAULT_PAGE_SIZE = 20; export const DEFAULT_DATE_COMPARE = 'prev'; +export const DEFAULT_CURRENCY = 'USD'; export const REALTIME_RANGE = 30; export const REALTIME_INTERVAL = 10000; diff --git a/src/lib/format.ts b/src/lib/format.ts index 52fd3048d..035a18111 100644 --- a/src/lib/format.ts +++ b/src/lib/format.ts @@ -1,3 +1,5 @@ +import { DEFAULT_CURRENCY } from './constants'; + export function parseTime(val: number) { const days = ~~(val / 86400); const hours = ~~(val / 3600) - days * 24; @@ -94,7 +96,7 @@ export function formatCurrency(value: number, currency: string, locale = 'en-US' // Fallback to default currency format if an error occurs formattedValue = new Intl.NumberFormat(locale, { style: 'currency', - currency: 'USD', + currency: DEFAULT_CURRENCY, }); } From 97c26bc0759caabdde17d0e35c829bb0b0e424d6 Mon Sep 17 00:00:00 2001 From: Dimitar Yanakiev Date: Fri, 26 Dec 2025 16:34:38 +0200 Subject: [PATCH 031/412] Translated various labels and messages in Bulgarian. --- src/lang/bg-BG.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/lang/bg-BG.json b/src/lang/bg-BG.json index 4b0effc89..50099032f 100644 --- a/src/lang/bg-BG.json +++ b/src/lang/bg-BG.json @@ -93,7 +93,7 @@ "label.event-name": "Име на събитие", "label.events": "Събития", "label.exists": "Съществува", - "label.exit": "Exit URL", + "label.exit": "URL за изход", "label.false": "Грешно", "label.field": "Поле", "label.fields": "Полета", @@ -135,7 +135,7 @@ "label.last-days": "Последните {x} дни", "label.last-hours": "Последните {x} часа", "label.last-months": "Последните {x} месеца", - "label.last-seen": "Last seen", + "label.last-seen": "Последно видяно", "label.leave": "Напусни", "label.leave-team": "Напусни екип", "label.less-than": "По-малко от", @@ -161,7 +161,7 @@ "label.none": "Няма", "label.number-of-records": "{x} {x, plural, one {един} other {други}}", "label.ok": "Добре", - "label.online": "Online", + "label.online": "Онлайн", "label.organic-search": "Органично търсене", "label.organic-shopping": "Органично пазаруване", "label.organic-social": "Органични социални мрежи", @@ -185,9 +185,9 @@ "label.paths": "Пътища", "label.pixels": "Пиксели", "label.powered-by": "Поддържано от {name}", - "label.previous": "Previous", - "label.previous-period": "Previous period", - "label.previous-year": "Previous year", + "label.previous": "Предишен", + "label.previous-period": "Предишен период", + "label.previous-year": "Предишна година", "label.profile": "Профил", "label.properties": "Свойства", "label.property": "Свойство", @@ -211,8 +211,8 @@ "label.reset-website": "Нулирай уебсайт", "label.retention": "Привързване", "label.retention-description": "Измерете привързаността към вашия уебсайт, като проследявате колко често потребителите се връщат.", - "label.revenue": "Revenue", - "label.revenue-description": "Look into your revenue across time.", + "label.revenue": "Приходи", + "label.revenue-description": "Прегледайте приходите си във времето.", "label.role": "Роля", "label.run-query": "Изпълни запитване", "label.save": "Запази", @@ -260,14 +260,14 @@ "label.total": "Общо", "label.total-records": "Общо записи", "label.tracking-code": "Код за проследяване", - "label.transactions": "Transactions", + "label.transactions": "Транзакции", "label.transfer": "Прехвърли", "label.transfer-website": "Прехвърляне на уебсайт", "label.true": "Вярно", "label.type": "Вид", "label.unique": "Уникален", "label.unique-visitors": "Уникални посетители", - "label.uniqueCustomers": "Unique Customers", + "label.uniqueCustomers": "Уникални клиенти", "label.unknown": "Неизвестен", "label.untitled": "Без заглавие", "label.update": "Актуализирай", @@ -282,7 +282,7 @@ "label.view-only": "Само за преглед", "label.views": "Прегледи", "label.views-per-visit": "Прегледи на посещение", - "label.visit-duration": "Visit duration", + "label.visit-duration": "Продължителност на посещение", "label.visitors": "Посетители", "label.visits": "Посещения", "label.website": "Уебсайт", @@ -292,8 +292,8 @@ "label.yesterday": "Вчера", "message.action-confirmation": "Въведете {confirmation} в полето по-долу, за да потвърдите.", "message.active-users": "{x} {x, plural, one {активен един} other {активни други}}", - "message.bad-request": "Bad request", - "message.collected-data": "Collected data", + "message.bad-request": "Невалидна заявка", + "message.collected-data": "Събрани данни", "message.confirm-delete": "Сигурни ли сте, че искате да изтриете {target}?", "message.confirm-leave": "Сигурни ли сте, че искате да напуснете {target}?", "message.confirm-remove": "Сигурни ли сте, че искате да премахнете {target}?", @@ -302,7 +302,7 @@ "message.delete-website-warning": "Всички данни за уебсайта ще бъдат изтрити.", "message.error": "Възникна грешка.", "message.event-log": "{event} на {url}", - "message.forbidden": "Forbidden", + "message.forbidden": "Забранено", "message.go-to-settings": "Отидете в настройките", "message.incorrect-username-password": "Неправилно потребителско име и/или парола.", "message.invalid-domain": "Невалиден домейн. Не включвайте http/https.", @@ -316,13 +316,13 @@ "message.no-teams": "Няма създадени екипи.", "message.no-users": "Няма потребители.", "message.no-websites-configured": "Нямате конфигурирани уебсайтове.", - "message.not-found": "Not found", - "message.nothing-selected": "Nothing selected.", + "message.not-found": "Не е намерено", + "message.nothing-selected": "Няма избрано.", "message.page-not-found": "Страницата не е намерена", "message.reset-website": "За да нулирате този уебсайт, въведете {confirmation} в полето по-долу, за да потвърдите.", "message.reset-website-warning": "Всички статистически данни за този уебсайт ще бъдат изтрити, но вашите настройки ще останат непроменени.", "message.saved": "Запазено.", - "message.sever-error": "Server error", + "message.sever-error": "Сървърна грешка", "message.share-url": "Статистиката за вашия уебсайт е публично достъпна на следния URL адрес:", "message.team-already-member": "Вече сте член на екипа.", "message.team-not-found": "Екипът не е намерен.", @@ -332,7 +332,7 @@ "message.transfer-user-website-to-team": "Изберете екипът на който да бъде прехвърлен уебсайта.", "message.transfer-website": "Прехвърли собствеността на уебсайта към вашия акаунт или към друг екип.", "message.triggered-event": "Активирано събитие", - "message.unauthorized": "Unauthorized", + "message.unauthorized": "Неоторизиран достъп", "message.user-deleted": "Потребителят е изтрит.", "message.viewed-page": "Страницата е видяна", "message.visitor-log": "Посетител от {country}, използващ {browser} на {os} {device}" From b0aa6fd6efa55fbb5402d3a171ff3e1fcf251b41 Mon Sep 17 00:00:00 2001 From: Yash Date: Fri, 26 Dec 2025 22:13:23 +0530 Subject: [PATCH 032/412] feat: Add current version to API response --- src/app/api/config/route.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/api/config/route.ts b/src/app/api/config/route.ts index 4e40caa4b..101a12243 100644 --- a/src/app/api/config/route.ts +++ b/src/app/api/config/route.ts @@ -17,5 +17,6 @@ export async function GET(request: Request) { telemetryDisabled: !!process.env.DISABLE_TELEMETRY, trackerScriptName: process.env.TRACKER_SCRIPT_NAME, updatesDisabled: !!process.env.DISABLE_UPDATES, + currentVersion: !!process.env.currentVersion, }); } From 8286af1453f6eaa159b5183a48ccbc572589b532 Mon Sep 17 00:00:00 2001 From: SBOZH Date: Thu, 1 Jan 2026 15:53:20 +0100 Subject: [PATCH 033/412] Fixed PostgreSQL 12/13 syntax error in Journeys feature --- src/queries/sql/reports/getJourney.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries/sql/reports/getJourney.ts b/src/queries/sql/reports/getJourney.ts index 283e0fad4..21a7f22dc 100644 --- a/src/queries/sql/reports/getJourney.ts +++ b/src/queries/sql/reports/getJourney.ts @@ -119,7 +119,7 @@ async function relationalQuery( select distinct website_event.visit_id, website_event.referrer_path, - coalesce(nullIf(website_event.event_name, ''), website_event.url_path) event, + coalesce(nullIf(website_event.event_name, ''), website_event.url_path) "event", row_number() OVER (PARTITION BY visit_id ORDER BY website_event.created_at) AS event_number from website_event ${cohortQuery} From dacf13475ad152fce7ca2d03c56a7b477a1d0313 Mon Sep 17 00:00:00 2001 From: AymanAlSuleihi Date: Thu, 1 Jan 2026 15:01:04 +0000 Subject: [PATCH 034/412] Add country image t1.png for Tor --- public/images/country/t1.png | Bin 0 -> 1117 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/country/t1.png diff --git a/public/images/country/t1.png b/public/images/country/t1.png new file mode 100644 index 0000000000000000000000000000000000000000..c45ed0fe9f57d60463fe6755b7a44fec9d9c5b74 GIT binary patch literal 1117 zcmV-j1fu(iP)!MXa?E&`KeKCO|+4Dw-ILT#7MD3<5V&WhLuvuP-}$ zXKzJH$xv;myQs&r_JT;6w#?0oNp4=0C@2KOfs__f&swJQWum~?zwZ1)&d{tf6u52t zi6ugjTb-;d4+KCV074;DC9!)Yo+ALzqgo%HSp7!(v^^sNo0VoYF=5E;NQ^~TRX{g=b65I0%NC^apCY4 z+S_`VxpE@u-a)#~CnJiZUQnO9|D`Qf&aM$cj0*Im!?n{%F1Bv{v;a@PJq<+{TsnG%qIiT*nZ}K)eFQXxaD_%Ln=RHn96UwB@Pip9 ziNwXhpGA| Date: Sat, 3 Jan 2026 00:48:09 +0000 Subject: [PATCH 035/412] Fix double scrollbar in dropdown --- src/components/input/WebsiteSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index 8d81eb9a0..04c773a71 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -65,7 +65,7 @@ export function WebsiteSelect({ renderValue={renderValue} listProps={{ renderEmptyState: () => , - style: { maxHeight: '400px' }, + style: { maxHeight: 'calc(42vh - 65px)' }, }} > {({ id, name }: any) => {name}} From fbe031bfe990c2aefeebc85f0f90f7c54d13b49c Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 7 Jan 2026 09:30:59 -0800 Subject: [PATCH 036/412] update pixel/link edit form on save. --- src/app/(main)/links/LinkDeleteButton.tsx | 5 +++-- src/app/(main)/links/LinkEditForm.tsx | 1 + src/app/(main)/pixels/PixelEditForm.tsx | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/(main)/links/LinkDeleteButton.tsx b/src/app/(main)/links/LinkDeleteButton.tsx index 78f85f891..32ccbaf7e 100644 --- a/src/app/(main)/links/LinkDeleteButton.tsx +++ b/src/app/(main)/links/LinkDeleteButton.tsx @@ -1,5 +1,5 @@ import { ConfirmationForm } from '@/components/common/ConfirmationForm'; -import { useDeleteQuery, useMessages } from '@/components/hooks'; +import { useDeleteQuery, useMessages, useModified } from '@/components/hooks'; import { Trash } from '@/components/icons'; import { DialogButton } from '@/components/input/DialogButton'; import { messages } from '@/components/messages'; @@ -15,7 +15,8 @@ export function LinkDeleteButton({ onSave?: () => void; }) { const { formatMessage, labels, getErrorMessage, FormattedMessage } = useMessages(); - const { mutateAsync, isPending, error, touch } = useDeleteQuery(`/links/${linkId}`); + const { mutateAsync, isPending, error } = useDeleteQuery(`/links/${linkId}`); + const { touch } = useModified(); const handleConfirm = async (close: () => void) => { await mutateAsync(null, { diff --git a/src/app/(main)/links/LinkEditForm.tsx b/src/app/(main)/links/LinkEditForm.tsx index e9ad18f4f..a6c0164d0 100644 --- a/src/app/(main)/links/LinkEditForm.tsx +++ b/src/app/(main)/links/LinkEditForm.tsx @@ -50,6 +50,7 @@ export function LinkEditForm({ onSuccess: async () => { toast(formatMessage(messages.saved)); touch('links'); + touch(`link:${linkId}`); onSave?.(); onClose?.(); }, diff --git a/src/app/(main)/pixels/PixelEditForm.tsx b/src/app/(main)/pixels/PixelEditForm.tsx index aedd3a3b6..46241c1cf 100644 --- a/src/app/(main)/pixels/PixelEditForm.tsx +++ b/src/app/(main)/pixels/PixelEditForm.tsx @@ -48,6 +48,7 @@ export function PixelEditForm({ onSuccess: async () => { toast(formatMessage(messages.saved)); touch('pixels'); + touch(`pixel:${pixelId}`); onSave?.(); onClose?.(); }, From fbf03d65636c5368e5daa4844b81abed4671830d Mon Sep 17 00:00:00 2001 From: AymanAlSuleihi Date: Fri, 9 Jan 2026 19:25:07 +0000 Subject: [PATCH 037/412] Fix metrics bar not updating on compare mode switch --- src/app/api/websites/[websiteId]/stats/route.ts | 7 ++++++- src/components/hooks/queries/useWebsiteStatsQuery.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 07c8b9699..09d691f1c 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -12,6 +12,7 @@ export async function GET( ) { const schema = z.object({ ...dateRangeParams, + compare: z.enum(['prev', 'yoy']).optional(), ...filterParams, }); @@ -31,7 +32,11 @@ export async function GET( const data = await getWebsiteStats(websiteId, filters); - const { startDate, endDate } = getCompareDate('prev', filters.startDate, filters.endDate); + const { startDate, endDate } = getCompareDate( + filters.compare || 'prev', + filters.startDate, + filters.endDate, + ); const comparison = await getWebsiteStats(websiteId, { ...filters, diff --git a/src/components/hooks/queries/useWebsiteStatsQuery.ts b/src/components/hooks/queries/useWebsiteStatsQuery.ts index e9a0c48ca..69bae09f6 100644 --- a/src/components/hooks/queries/useWebsiteStatsQuery.ts +++ b/src/components/hooks/queries/useWebsiteStatsQuery.ts @@ -1,5 +1,6 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useDateParameters } from '@/components/hooks/useDateParameters'; +import { useDateRange } from '@/components/hooks/useDateRange'; import { useApi } from '../useApi'; import { useFilterParameters } from '../useFilterParameters'; @@ -24,12 +25,16 @@ export function useWebsiteStatsQuery( ) { const { get, useQuery } = useApi(); const { startAt, endAt, unit, timezone } = useDateParameters(); + const { compare } = useDateRange(); const filters = useFilterParameters(); return useQuery({ - queryKey: ['websites:stats', { websiteId, startAt, endAt, unit, timezone, ...filters }], + queryKey: [ + 'websites:stats', + { websiteId, startAt, endAt, unit, timezone, compare, ...filters }, + ], queryFn: () => - get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, ...filters }), + get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, compare, ...filters }), enabled: !!websiteId, ...options, }); From 6420f2c81338705d1ad83295fb5b53dcfb8aa8b1 Mon Sep 17 00:00:00 2001 From: AymanAlSuleihi Date: Fri, 9 Jan 2026 22:54:50 +0000 Subject: [PATCH 038/412] Remove redundant compare param definition --- src/app/api/websites/[websiteId]/stats/route.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 09d691f1c..12492537e 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -12,7 +12,6 @@ export async function GET( ) { const schema = z.object({ ...dateRangeParams, - compare: z.enum(['prev', 'yoy']).optional(), ...filterParams, }); @@ -32,11 +31,9 @@ export async function GET( const data = await getWebsiteStats(websiteId, filters); - const { startDate, endDate } = getCompareDate( - filters.compare || 'prev', - filters.startDate, - filters.endDate, - ); + const compare = filters.compare === 'yoy' ? 'yoy' : 'prev'; + + const { startDate, endDate } = getCompareDate(compare, filters.startDate, filters.endDate); const comparison = await getWebsiteStats(websiteId, { ...filters, From a049fbb5b0b2e8c3325f058bea26050c849bd91f Mon Sep 17 00:00:00 2001 From: AymanAlSuleihi Date: Fri, 9 Jan 2026 23:41:16 +0000 Subject: [PATCH 039/412] Update compare parameter to use enum for valid values --- src/app/api/websites/[websiteId]/stats/route.ts | 2 +- src/lib/schema.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 12492537e..b7177b5d8 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -31,7 +31,7 @@ export async function GET( const data = await getWebsiteStats(websiteId, filters); - const compare = filters.compare === 'yoy' ? 'yoy' : 'prev'; + const compare = filters.compare ?? 'prev'; const { startDate, endDate } = getCompareDate(compare, filters.startDate, filters.endDate); diff --git a/src/lib/schema.ts b/src/lib/schema.ts index 38f7339a1..aafd8e43f 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -20,7 +20,7 @@ export const dateRangeParams = { endDate: z.coerce.date().optional(), timezone: timezoneParam.optional(), unit: unitParam.optional(), - compare: z.string().optional(), + compare: z.enum(['prev', 'yoy']).optional(), }; export const filterParams = { From 1a664d8719ccd2243bed2c6a8c87e083a317b40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jere=20M=C3=A4ennen=C3=A4?= Date: Sun, 11 Jan 2026 14:25:41 +0200 Subject: [PATCH 040/412] Update fi-FI.json --- src/lang/fi-FI.json | 168 ++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/src/lang/fi-FI.json b/src/lang/fi-FI.json index daaa62f0d..686294701 100644 --- a/src/lang/fi-FI.json +++ b/src/lang/fi-FI.json @@ -37,7 +37,7 @@ "label.compare-dates": "Vertaa päivämääriä", "label.confirm": "Vahvista", "label.confirm-password": "Vahvista salasana", - "label.contains": "Contains", + "label.contains": "Sisältää", "label.content": "Sisältö", "label.continue": "Jatka", "label.conversion": "Konversio", @@ -96,7 +96,7 @@ "label.false": "Epätosi", "label.field": "Kenttä", "label.fields": "Kentät", - "label.filter": "Filter", + "label.filter": "Suodatin", "label.filter-combined": "Yhdistetty", "label.filter-raw": "Käsittelemätön", "label.filters": "Suodattimet", @@ -151,7 +151,7 @@ "label.members": "Jäsenet", "label.min": "Minimi", "label.mobile": "Puhelin", - "label.model": "Model", + "label.model": "Malli", "label.more": "Lisää", "label.my-account": "Oma tili", "label.my-websites": "Omat verkkosivut", @@ -184,9 +184,9 @@ "label.paths": "Polut", "label.pixels": "Pikselit", "label.powered-by": "Voimanlähteenä {name}", - "label.previous": "Previous", - "label.previous-period": "Previous period", - "label.previous-year": "Previous year", + "label.previous": "Edellinen", + "label.previous-period": "Edellinen ajanjakso", + "label.previous-year": "Edellinen vuosi", "label.profile": "Profiili", "label.properties": "Ominaisuudet", "label.property": "Ominaisuus", @@ -195,16 +195,16 @@ "label.query-parameters": "Kyselyn parametrit", "label.realtime": "Juuri nyt", "label.referral": "Viittaus", - "label.referrer": "Referrer", + "label.referrer": "Viittaaja", "label.referrers": "Viittaajat", "label.refresh": "Päivitä", - "label.regenerate": "Regenerate", - "label.region": "Region", - "label.regions": "Regions", + "label.regenerate": "Luo uudelleen", + "label.region": "Alue", + "label.regions": "Alueet", "label.remaining": "Jäljellä", - "label.remove": "Remove", - "label.remove-member": "Remove member", - "label.reports": "Reports", + "label.remove": "Poista", + "label.remove-member": "Poista jäsen", + "label.reports": "Raportit", "label.required": "Vaaditaan", "label.reset": "Nollaa", "label.reset-website": "Nollaa tilastot", @@ -212,19 +212,19 @@ "label.retention-description": "Measure your website stickiness by tracking how often users return.", "label.revenue": "Tulot", "label.revenue-description": "Katso tulosi ajan mittaan.", - "label.role": "Role", - "label.run-query": "Run query", + "label.role": "Rooli", + "label.run-query": "Suorita kysely", "label.save": "Tallenna", "label.screens": "Näytöt", - "label.search": "Search", - "label.select": "Select", - "label.select-date": "Select date", + "label.search": "Haku", + "label.select": "Valitse", + "label.select-date": "Valitse päivämäärä", "label.select-filter": "Valitse suodatin", - "label.select-role": "Select role", - "label.select-website": "Select website", + "label.select-role": "Valitse rooli", + "label.select-website": "Valitse verkkosivu", "label.session": "Istunto", "label.session-data": "Istuntotiedot", - "label.sessions": "Sessions", + "label.sessions": "Istunnot", "label.settings": "Asetukset", "label.share": "Jaa", "label.share-url": "Jaa URL", @@ -233,107 +233,107 @@ "label.sources": "Lähteet", "label.start-step": "Aloitusvaihe", "label.steps": "Vaiheet", - "label.sum": "Sum", + "label.sum": "Summa", "label.tablet": "Tabletti", "label.tag": "Tunniste", "label.tags": "Tunnisteet", - "label.team": "Team", - "label.team-id": "Team ID", - "label.team-manager": "Team manager", - "label.team-member": "Team member", - "label.team-name": "Team name", - "label.team-owner": "Team owner", + "label.team": "Tiimi", + "label.team-id": "Tiimin ID", + "label.team-manager": "Tiimin johtaja", + "label.team-member": "Tiimin jäsen", + "label.team-name": "Tiimin nimi", + "label.team-owner": "Tiimin omistaja", "label.team-settings": "Tiimin asetukset", "label.team-view-only": "Team view only", - "label.team-websites": "Team websites", - "label.teams": "Teams", + "label.team-websites": "Tiimin verkkosivut", + "label.teams": "Tiimit", "label.terms": "Ehdot", "label.theme": "Teema", "label.this-month": "Tämä kuukausi", "label.this-week": "Tämä viikko", "label.this-year": "Tämä vuosi", "label.timezone": "Aikavyöhyke", - "label.title": "Title", + "label.title": "Otsikko", "label.today": "Tänään", "label.toggle-charts": "Kytke kaaviot päälle/pois", - "label.total": "Total", - "label.total-records": "Total records", + "label.total": "Yhteensä", + "label.total-records": "Tietueita yhteensä", "label.tracking-code": "Seurantakoodi", - "label.transactions": "Transactions", - "label.transfer": "Transfer", - "label.transfer-website": "Transfer website", - "label.true": "True", - "label.type": "Type", - "label.unique": "Unique", + "label.transactions": "Transaktiot", + "label.transfer": "Siirrä", + "label.transfer-website": "Siirrä verkkosivu", + "label.true": "Tosi", + "label.type": "Tyyppi", + "label.unique": "Uniikki", "label.unique-visitors": "Yksittäiset kävijät", - "label.uniqueCustomers": "Unique Customers", + "label.uniqueCustomers": "Uniikit asiakkaat", "label.unknown": "Tuntematon", - "label.untitled": "Untitled", - "label.update": "Update", - "label.user": "User", + "label.untitled": "Nimetön", + "label.update": "Päivitä", + "label.user": "Käyttäjä", "label.username": "Käyttäjänimi", - "label.users": "Users", + "label.users": "Käyttäjät", "label.utm": "UTM", - "label.utm-description": "Track your campaigns through UTM parameters.", - "label.value": "Value", - "label.view": "View", + "label.utm-description": "Seuraa kampanjoitasi UTM-parametrien avulla.", + "label.value": "Arvo", + "label.view": "Näytä", "label.view-details": "Katso tiedot", - "label.view-only": "View only", + "label.view-only": "Vain katselu", "label.views": "Näyttökerrat", - "label.views-per-visit": "Views per visit", + "label.views-per-visit": "Katselukerrat vierailua kohti", "label.visit-duration": "Keskimääräinen vierailuaika", "label.visitors": "Vierailijat", - "label.visits": "Visits", - "label.website": "Website", - "label.website-id": "Website ID", + "label.visits": "Vierailut", + "label.website": "Verkkosivu", + "label.website-id": "Verkkosivun ID", "label.websites": "Verkkosivut", - "label.window": "Window", - "label.yesterday": "Yesterday", - "label.behavior": "Behavior", - "message.action-confirmation": "Type {confirmation} in the box below to confirm.", + "label.window": "Ikkuna", + "label.yesterday": "Eilen", + "label.behavior": "Käyttäytyminen", + "message.action-confirmation": "Kirjoita {confirmation} alla olevaan kenttään vahvistaaksesi.", "message.active-users": "{x} {x, plural, one {vierailija} other {vierailijaa}}", - "message.bad-request": "Bad request", - "message.collected-data": "Collected data", + "message.bad-request": "Virheellinen pyyntö", + "message.collected-data": "Kerätty data", "message.confirm-delete": "Haluatko varmasti poistaa sivuston {target}?", - "message.confirm-leave": "Are you sure you want to leave {target}?", - "message.confirm-remove": "Are you sure you want to remove {target}?", + "message.confirm-leave": "Haluatko varmasti poistua {target}?", + "message.confirm-remove": "Haluatko varmasti poistaa {target}?", "message.confirm-reset": "Haluatko varmasti poistaa sivuston {target} tilastot?", - "message.delete-team-warning": "Deleting a team will also delete all team websites.", + "message.delete-team-warning": "Tiimin poistaminen poistaa myös kaikki tiimin sivustot.", "message.delete-website-warning": "Kaikki siihen liittyvät tiedot poistetaan.", "message.error": "Jotain meni pieleen.", "message.event-log": "{event} on {url}", - "message.forbidden": "Forbidden", + "message.forbidden": "Kielletty", "message.go-to-settings": "Mene asetuksiin", "message.incorrect-username-password": "Väärä käyttäjänimi/salasana.", "message.invalid-domain": "Virheellinen verkkotunnus", - "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.min-password-length": "Vähimmäispituus {n} merkkiä", + "message.new-version-available": "Umamista on saatavilla uusi versio {version}!", "message.no-data-available": "Tietoja ei ole käytettävissä.", - "message.no-event-data": "No event data is available.", + "message.no-event-data": "Tapahtumatietoja ei ole saatavilla.", "message.no-match-password": "Salasanat eivät täsmää", - "message.no-results-found": "No results were found.", - "message.no-team-websites": "This team does not have any websites.", - "message.no-teams": "You have not created any teams.", - "message.no-users": "There are no users.", + "message.no-results-found": "Tuloksia ei löytynyt.", + "message.no-team-websites": "Tällä tiimillä ei ole verkkosivustoja.", + "message.no-teams": "Et ole luonut yhtään tiimiä.", + "message.no-users": "Käyttäjiä ei ole.", "message.no-websites-configured": "Sinulla ei ole määritettyjä verkkosivustoja.", - "message.not-found": "Not found", - "message.nothing-selected": "Nothing selected.", + "message.not-found": "Ei löytynyt", + "message.nothing-selected": "Mitään ei ole valittu.", "message.page-not-found": "Sivua ei löydetty.", - "message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.", + "message.reset-website": "Nollaa verkkosivusto kirjoittamalla {confirmation} alla olevaan kenttään vahvistaaksesi.", "message.reset-website-warning": "Kaikki sivuston tilastot poistetaan, mutta seurantakoodi pysyy muuttumattomana.", "message.saved": "Tallennettu onnistuneesti.", - "message.sever-error": "Server error", + "message.sever-error": "Palvelinvirhe", "message.share-url": "Tämä on julkisesti jaettu URL sivustolle {target}.", - "message.team-already-member": "You are already a member of the team.", - "message.team-not-found": "Team not found.", - "message.team-websites-info": "Websites can be viewed by anyone on the team.", + "message.team-already-member": "Olet jo tiimissä.", + "message.team-not-found": "Tiimiä ei löydetty.", + "message.team-websites-info": "Verkkosivuja voi tarkastella kuka tahansa tiimin jäsen.", "message.tracking-code": "Seurantakoodi", - "message.transfer-team-website-to-user": "Transfer this website to your account?", - "message.transfer-user-website-to-team": "Select the team to transfer this website to.", - "message.transfer-website": "Transfer website ownership to your account or another team.", - "message.triggered-event": "Triggered event", - "message.unauthorized": "Unauthorized", - "message.user-deleted": "User deleted.", - "message.viewed-page": "Viewed page", + "message.transfer-team-website-to-user": "Siirretäänkö tämä verkkosivu tilillesi?", + "message.transfer-user-website-to-team": "Valitse tiimi, johon verkkosivusto siirretään.", + "message.transfer-website": "Siirrä verkkosivusto tiliisi tai toiselle tiimille.", + "message.triggered-event": "Laukaistu tapahtuma", + "message.unauthorized": "Ei oikeuksia", + "message.user-deleted": "Käyttäjä poistettu.", + "message.viewed-page": "Katsottu sivu", "message.visitor-log": "Vierailija maasta {country} selaimella {browser} laitteella {os} {device}" -} +} \ No newline at end of file From ebfbc282eebbe9dd87f6255129bc6417549faa3a Mon Sep 17 00:00:00 2001 From: Dorian TETU Date: Tue, 13 Jan 2026 16:39:39 +0100 Subject: [PATCH 041/412] fix: autofill background color --- src/styles/global.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/styles/global.css b/src/styles/global.css index e9fca9fdf..6e767563b 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -41,3 +41,18 @@ a:hover { border: 4px solid rgba(0, 0, 0, 0); background-clip: padding-box; } + +/* Fix autofill background color to match dark theme */ +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +input:-webkit-autofill:active, +textarea:-webkit-autofill, +textarea:-webkit-autofill:hover, +textarea:-webkit-autofill:focus, +select:-webkit-autofill, +select:-webkit-autofill:hover, +select:-webkit-autofill:focus { + -webkit-box-shadow: 0 0 0 1000px var(--background-color) inset !important; + transition: color 5000s ease-in-out 0s; +} From b6013c3ee8d21a6b82efc398e2fa103c71a9e425 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 14 Jan 2026 10:28:48 -0800 Subject: [PATCH 042/412] Revert "refactor 6 month retention. use auth instead of cache:website". Fix share page retention bug. This reverts commit 741c6039e60020e62dd81c20f3f01e365d7d2b73. --- src/app/api/reports/attribution/route.ts | 4 ++-- src/app/api/reports/breakdown/route.ts | 4 ++-- src/app/api/reports/funnel/route.ts | 4 ++-- src/app/api/reports/goal/route.ts | 4 ++-- src/app/api/reports/retention/route.ts | 4 ++-- src/app/api/reports/revenue/route.ts | 4 ++-- src/app/api/reports/utm/route.ts | 4 ++-- .../api/websites/[websiteId]/event-data/events/route.ts | 2 +- .../api/websites/[websiteId]/event-data/fields/route.ts | 2 +- .../websites/[websiteId]/event-data/properties/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/stats/route.ts | 2 +- .../api/websites/[websiteId]/event-data/values/route.ts | 2 +- src/app/api/websites/[websiteId]/events/route.ts | 2 +- src/app/api/websites/[websiteId]/events/series/route.ts | 2 +- src/app/api/websites/[websiteId]/export/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/expanded/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/route.ts | 2 +- src/app/api/websites/[websiteId]/pageviews/route.ts | 2 +- .../websites/[websiteId]/session-data/properties/route.ts | 2 +- .../api/websites/[websiteId]/session-data/values/route.ts | 2 +- .../[websiteId]/sessions/[sessionId]/activity/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/weekly/route.ts | 2 +- src/app/api/websites/[websiteId]/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/values/route.ts | 2 +- src/lib/request.ts | 7 +++---- 27 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index ab9b1ddbc..bd7d86dc7 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getAttribution(websiteId, parameters as AttributionParameters, filters); diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index a06636c74..3c5931458 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters); diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index f6e210293..c13f6f1c8 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getFunnel(websiteId, parameters as FunnelParameters, filters); diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index db2aabcef..3bd0415d6 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getGoal(websiteId, parameters as GoalParameters, filters); diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index 5adf7bb85..d1a7d698b 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, body.parameters); const data = await getRetention(websiteId, parameters as RetentionParameters, filters); diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index f4146b966..6a556612b 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getRevenue(websiteId, parameters as RevenuParameters, filters); diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index d4af4da06..577fdab79 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -18,8 +18,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, body.parameters); const data = { utm_source: [], diff --git a/src/app/api/websites/[websiteId]/event-data/events/route.ts b/src/app/api/websites/[websiteId]/event-data/events/route.ts index 444afa273..eb6ee6ed8 100644 --- a/src/app/api/websites/[websiteId]/event-data/events/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/events/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataEvents(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/event-data/fields/route.ts b/src/app/api/websites/[websiteId]/event-data/fields/route.ts index e034d9375..bce6a977c 100644 --- a/src/app/api/websites/[websiteId]/event-data/fields/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/fields/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataFields(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/properties/route.ts b/src/app/api/websites/[websiteId]/event-data/properties/route.ts index 29719fb22..52d15cfbd 100644 --- a/src/app/api/websites/[websiteId]/event-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/stats/route.ts b/src/app/api/websites/[websiteId]/event-data/stats/route.ts index 1d1e76dff..042e989a4 100644 --- a/src/app/api/websites/[websiteId]/event-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/values/route.ts b/src/app/api/websites/[websiteId]/event-data/values/route.ts index ed01fb2b6..12e8f2dc0 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -30,7 +30,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/events/route.ts b/src/app/api/websites/[websiteId]/events/route.ts index dfabb87fb..74ec3ece4 100644 --- a/src/app/api/websites/[websiteId]/events/route.ts +++ b/src/app/api/websites/[websiteId]/events/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteEvents(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/events/series/route.ts b/src/app/api/websites/[websiteId]/events/series/route.ts index d5b925590..977e9c813 100644 --- a/src/app/api/websites/[websiteId]/events/series/route.ts +++ b/src/app/api/websites/[websiteId]/events/series/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/export/route.ts b/src/app/api/websites/[websiteId]/export/route.ts index f9749f34e..eec81c6d4 100644 --- a/src/app/api/websites/[websiteId]/export/route.ts +++ b/src/app/api/websites/[websiteId]/export/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([ getEventMetrics(websiteId, { type: 'event' }, filters), diff --git a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts index 7e6fbbfdf..d52c17736 100644 --- a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/metrics/route.ts b/src/app/api/websites/[websiteId]/metrics/route.ts index 2d0e6a600..12784adbe 100644 --- a/src/app/api/websites/[websiteId]/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/pageviews/route.ts b/src/app/api/websites/[websiteId]/pageviews/route.ts index dc921bc0c..af59bce46 100644 --- a/src/app/api/websites/[websiteId]/pageviews/route.ts +++ b/src/app/api/websites/[websiteId]/pageviews/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const [pageviews, sessions] = await Promise.all([ getPageviewStats(websiteId, filters), diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index a0aed73ce..2d8db1535 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index db7106548..7d06870ac 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -29,7 +29,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts index 3e70bea0a..41b766d03 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts @@ -25,7 +25,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionActivity(websiteId, sessionId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/route.ts b/src/app/api/websites/[websiteId]/sessions/route.ts index f344476c3..ed4757a1c 100644 --- a/src/app/api/websites/[websiteId]/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteSessions(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/stats/route.ts b/src/app/api/websites/[websiteId]/sessions/stats/route.ts index 74b4e5e80..459830edf 100644 --- a/src/app/api/websites/[websiteId]/sessions/stats/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const metrics = await getWebsiteSessionStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index f6dfd206b..b9ccf3ef0 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWeeklyTraffic(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index a96fa5b06..b7177b5d8 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/values/route.ts b/src/app/api/websites/[websiteId]/values/route.ts index c2c95b375..172325e3f 100644 --- a/src/app/api/websites/[websiteId]/values/route.ts +++ b/src/app/api/websites/[websiteId]/values/route.ts @@ -42,7 +42,7 @@ export async function GET( value: segment.name, })); } else { - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); values = await getValues(websiteId, FILTER_COLUMNS[type], filters); } diff --git a/src/lib/request.ts b/src/lib/request.ts index d6543b184..7f9163cca 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -81,12 +81,12 @@ export function getRequestFilters(query: Record) { return result; } -export async function setWebsiteDate(websiteId: string, userId: string, data: Record) { +export async function setWebsiteDate(websiteId: string, data: Record) { const website = await fetchWebsite(websiteId); const cloudMode = !!process.env.CLOUD_MODE; if (cloudMode && website && !website.teamId) { - const account = await fetchAccount(userId); + const account = await fetchAccount(website.userId); if (!account?.hasSubscription) { data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6))); @@ -103,13 +103,12 @@ export async function setWebsiteDate(websiteId: string, userId: string, data: Re export async function getQueryFilters( params: Record, websiteId?: string, - userId?: string, ): Promise { const dateRange = getRequestDateRange(params); const filters = getRequestFilters(params); if (websiteId) { - await setWebsiteDate(websiteId, userId, dateRange); + await setWebsiteDate(websiteId, dateRange); if (params.segment) { const segmentParams = (await getWebsiteSegment(websiteId, params.segment)) From 2bd0734162c977ea68d4ce0ac17e9649a8ecdfe6 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 14 Jan 2026 10:28:48 -0800 Subject: [PATCH 043/412] Revert "refactor 6 month retention. use auth instead of cache:website". Fix share page retention bug. This reverts commit 741c6039e60020e62dd81c20f3f01e365d7d2b73. --- src/app/api/reports/attribution/route.ts | 4 ++-- src/app/api/reports/breakdown/route.ts | 4 ++-- src/app/api/reports/funnel/route.ts | 4 ++-- src/app/api/reports/goal/route.ts | 4 ++-- src/app/api/reports/retention/route.ts | 4 ++-- src/app/api/reports/revenue/route.ts | 4 ++-- src/app/api/reports/utm/route.ts | 4 ++-- .../api/websites/[websiteId]/event-data/events/route.ts | 2 +- .../api/websites/[websiteId]/event-data/fields/route.ts | 2 +- .../websites/[websiteId]/event-data/properties/route.ts | 2 +- src/app/api/websites/[websiteId]/event-data/stats/route.ts | 2 +- .../api/websites/[websiteId]/event-data/values/route.ts | 2 +- src/app/api/websites/[websiteId]/events/route.ts | 2 +- src/app/api/websites/[websiteId]/events/series/route.ts | 2 +- src/app/api/websites/[websiteId]/export/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/expanded/route.ts | 2 +- src/app/api/websites/[websiteId]/metrics/route.ts | 2 +- src/app/api/websites/[websiteId]/pageviews/route.ts | 2 +- .../websites/[websiteId]/session-data/properties/route.ts | 2 +- .../api/websites/[websiteId]/session-data/values/route.ts | 2 +- .../[websiteId]/sessions/[sessionId]/activity/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/sessions/weekly/route.ts | 2 +- src/app/api/websites/[websiteId]/stats/route.ts | 2 +- src/app/api/websites/[websiteId]/values/route.ts | 2 +- src/lib/request.ts | 7 +++---- 27 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/app/api/reports/attribution/route.ts b/src/app/api/reports/attribution/route.ts index ab9b1ddbc..bd7d86dc7 100644 --- a/src/app/api/reports/attribution/route.ts +++ b/src/app/api/reports/attribution/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getAttribution(websiteId, parameters as AttributionParameters, filters); diff --git a/src/app/api/reports/breakdown/route.ts b/src/app/api/reports/breakdown/route.ts index a06636c74..3c5931458 100644 --- a/src/app/api/reports/breakdown/route.ts +++ b/src/app/api/reports/breakdown/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters); diff --git a/src/app/api/reports/funnel/route.ts b/src/app/api/reports/funnel/route.ts index f6e210293..c13f6f1c8 100644 --- a/src/app/api/reports/funnel/route.ts +++ b/src/app/api/reports/funnel/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getFunnel(websiteId, parameters as FunnelParameters, filters); diff --git a/src/app/api/reports/goal/route.ts b/src/app/api/reports/goal/route.ts index db2aabcef..3bd0415d6 100644 --- a/src/app/api/reports/goal/route.ts +++ b/src/app/api/reports/goal/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getGoal(websiteId, parameters as GoalParameters, filters); diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts index 5adf7bb85..d1a7d698b 100644 --- a/src/app/api/reports/retention/route.ts +++ b/src/app/api/reports/retention/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, body.parameters); const data = await getRetention(websiteId, parameters as RetentionParameters, filters); diff --git a/src/app/api/reports/revenue/route.ts b/src/app/api/reports/revenue/route.ts index f4146b966..6a556612b 100644 --- a/src/app/api/reports/revenue/route.ts +++ b/src/app/api/reports/revenue/route.ts @@ -17,8 +17,8 @@ export async function POST(request: Request) { return unauthorized(); } - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); + const parameters = await setWebsiteDate(websiteId, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); const data = await getRevenue(websiteId, parameters as RevenuParameters, filters); diff --git a/src/app/api/reports/utm/route.ts b/src/app/api/reports/utm/route.ts index d4af4da06..577fdab79 100644 --- a/src/app/api/reports/utm/route.ts +++ b/src/app/api/reports/utm/route.ts @@ -18,8 +18,8 @@ export async function POST(request: Request) { return unauthorized(); } - const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id); - const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters); + const filters = await getQueryFilters(body.filters, websiteId); + const parameters = await setWebsiteDate(websiteId, body.parameters); const data = { utm_source: [], diff --git a/src/app/api/websites/[websiteId]/event-data/events/route.ts b/src/app/api/websites/[websiteId]/event-data/events/route.ts index 444afa273..eb6ee6ed8 100644 --- a/src/app/api/websites/[websiteId]/event-data/events/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/events/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataEvents(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/event-data/fields/route.ts b/src/app/api/websites/[websiteId]/event-data/fields/route.ts index e034d9375..bce6a977c 100644 --- a/src/app/api/websites/[websiteId]/event-data/fields/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/fields/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataFields(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/properties/route.ts b/src/app/api/websites/[websiteId]/event-data/properties/route.ts index 29719fb22..52d15cfbd 100644 --- a/src/app/api/websites/[websiteId]/event-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/stats/route.ts b/src/app/api/websites/[websiteId]/event-data/stats/route.ts index 1d1e76dff..042e989a4 100644 --- a/src/app/api/websites/[websiteId]/event-data/stats/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/event-data/values/route.ts b/src/app/api/websites/[websiteId]/event-data/values/route.ts index ed01fb2b6..12e8f2dc0 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -30,7 +30,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/events/route.ts b/src/app/api/websites/[websiteId]/events/route.ts index dfabb87fb..74ec3ece4 100644 --- a/src/app/api/websites/[websiteId]/events/route.ts +++ b/src/app/api/websites/[websiteId]/events/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteEvents(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/events/series/route.ts b/src/app/api/websites/[websiteId]/events/series/route.ts index d5b925590..977e9c813 100644 --- a/src/app/api/websites/[websiteId]/events/series/route.ts +++ b/src/app/api/websites/[websiteId]/events/series/route.ts @@ -29,7 +29,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getEventStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/export/route.ts b/src/app/api/websites/[websiteId]/export/route.ts index f9749f34e..eec81c6d4 100644 --- a/src/app/api/websites/[websiteId]/export/route.ts +++ b/src/app/api/websites/[websiteId]/export/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([ getEventMetrics(websiteId, { type: 'event' }, filters), diff --git a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts index 7e6fbbfdf..d52c17736 100644 --- a/src/app/api/websites/[websiteId]/metrics/expanded/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/expanded/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/metrics/route.ts b/src/app/api/websites/[websiteId]/metrics/route.ts index 2d0e6a600..12784adbe 100644 --- a/src/app/api/websites/[websiteId]/metrics/route.ts +++ b/src/app/api/websites/[websiteId]/metrics/route.ts @@ -37,7 +37,7 @@ export async function GET( } const { type, limit, offset, search } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); if (search) { filters[type] = `c.${search}`; diff --git a/src/app/api/websites/[websiteId]/pageviews/route.ts b/src/app/api/websites/[websiteId]/pageviews/route.ts index dc921bc0c..af59bce46 100644 --- a/src/app/api/websites/[websiteId]/pageviews/route.ts +++ b/src/app/api/websites/[websiteId]/pageviews/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const [pageviews, sessions] = await Promise.all([ getPageviewStats(websiteId, filters), diff --git a/src/app/api/websites/[websiteId]/session-data/properties/route.ts b/src/app/api/websites/[websiteId]/session-data/properties/route.ts index a0aed73ce..2d8db1535 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionDataProperties(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/session-data/values/route.ts b/src/app/api/websites/[websiteId]/session-data/values/route.ts index db7106548..7d06870ac 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -29,7 +29,7 @@ export async function GET( } const { propertyName } = query; - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionDataValues(websiteId, { ...filters, diff --git a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts index 3e70bea0a..41b766d03 100644 --- a/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts @@ -25,7 +25,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getSessionActivity(websiteId, sessionId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/route.ts b/src/app/api/websites/[websiteId]/sessions/route.ts index f344476c3..ed4757a1c 100644 --- a/src/app/api/websites/[websiteId]/sessions/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteSessions(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/stats/route.ts b/src/app/api/websites/[websiteId]/sessions/stats/route.ts index 74b4e5e80..459830edf 100644 --- a/src/app/api/websites/[websiteId]/sessions/stats/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const metrics = await getWebsiteSessionStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts index f6dfd206b..b9ccf3ef0 100644 --- a/src/app/api/websites/[websiteId]/sessions/weekly/route.ts +++ b/src/app/api/websites/[websiteId]/sessions/weekly/route.ts @@ -28,7 +28,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWeeklyTraffic(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 2bf862cdc..07c8b9699 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -27,7 +27,7 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); const data = await getWebsiteStats(websiteId, filters); diff --git a/src/app/api/websites/[websiteId]/values/route.ts b/src/app/api/websites/[websiteId]/values/route.ts index c2c95b375..172325e3f 100644 --- a/src/app/api/websites/[websiteId]/values/route.ts +++ b/src/app/api/websites/[websiteId]/values/route.ts @@ -42,7 +42,7 @@ export async function GET( value: segment.name, })); } else { - const filters = await getQueryFilters(query, websiteId, auth.user?.id); + const filters = await getQueryFilters(query, websiteId); values = await getValues(websiteId, FILTER_COLUMNS[type], filters); } diff --git a/src/lib/request.ts b/src/lib/request.ts index d6543b184..7f9163cca 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -81,12 +81,12 @@ export function getRequestFilters(query: Record) { return result; } -export async function setWebsiteDate(websiteId: string, userId: string, data: Record) { +export async function setWebsiteDate(websiteId: string, data: Record) { const website = await fetchWebsite(websiteId); const cloudMode = !!process.env.CLOUD_MODE; if (cloudMode && website && !website.teamId) { - const account = await fetchAccount(userId); + const account = await fetchAccount(website.userId); if (!account?.hasSubscription) { data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6))); @@ -103,13 +103,12 @@ export async function setWebsiteDate(websiteId: string, userId: string, data: Re export async function getQueryFilters( params: Record, websiteId?: string, - userId?: string, ): Promise { const dateRange = getRequestDateRange(params); const filters = getRequestFilters(params); if (websiteId) { - await setWebsiteDate(websiteId, userId, dateRange); + await setWebsiteDate(websiteId, dateRange); if (params.segment) { const segmentParams = (await getWebsiteSegment(websiteId, params.segment)) From 1e0620c544954003ff8b3015b4f6ebb3e45f9092 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 14 Jan 2026 12:53:13 -0800 Subject: [PATCH 044/412] Updated packages. --- package.json | 34 +- pnpm-lock.yaml | 3286 ++++++++++++++++++++++-------------------------- 2 files changed, 1533 insertions(+), 1787 deletions(-) diff --git a/package.json b/package.json index c4c832c0c..e9d91cb2e 100644 --- a/package.json +++ b/package.json @@ -61,18 +61,18 @@ ".next/cache" ], "dependencies": { - "@clickhouse/client": "^1.12.0", + "@clickhouse/client": "^1.16.0", "@date-fns/utc": "^1.2.0", "@dicebear/collection": "^9.2.3", "@dicebear/core": "^9.2.3", "@fontsource/inter": "^5.2.8", "@hello-pangea/dnd": "^17.0.0", - "@prisma/adapter-pg": "^7.1.0", - "@prisma/client": "^7.1.0", + "@prisma/adapter-pg": "^7.2.0", + "@prisma/client": "^7.2.0", "@prisma/extension-read-replicas": "^0.5.0", "@react-spring/web": "^10.0.3", "@svgr/cli": "^8.1.0", - "@tanstack/react-query": "^5.90.12", + "@tanstack/react-query": "^5.90.17", "@umami/react-zen": "^0.216.0", "@umami/redis-client": "^0.30.0", "bcryptjs": "^3.0.2", @@ -90,7 +90,7 @@ "detect-browser": "^5.2.0", "dotenv": "^17.2.3", "esbuild": "^0.25.11", - "fs-extra": "^11.3.2", + "fs-extra": "^11.3.3", "immer": "^10.2.0", "ipaddr.js": "^2.3.0", "is-ci": "^3.0.1", @@ -101,13 +101,13 @@ "jszip": "^3.10.1", "kafkajs": "^2.1.0", "lucide-react": "^0.543.0", - "maxmind": "^5.0.0", + "maxmind": "^5.0.3", "next": "^15.5.9", "node-fetch": "^3.2.8", "npm-run-all": "^4.1.5", "papaparse": "^5.5.3", - "pg": "^8.16.3", - "prisma": "^7.1.0", + "pg": "^8.17.0", + "prisma": "^7.2.0", "pure-rand": "^7.0.1", "react": "^19.2.3", "react-dom": "^19.2.3", @@ -120,15 +120,15 @@ "semver": "^7.7.3", "serialize-error": "^12.0.0", "thenby": "^1.3.4", - "ua-parser-js": "^2.0.6", + "ua-parser-js": "^2.0.8", "uuid": "^13.0.0", - "zod": "^4.1.13", - "zustand": "^5.0.9" + "zod": "^4.3.5", + "zustand": "^5.0.10" }, "devDependencies": { - "@biomejs/biome": "^2.3.8", + "@biomejs/biome": "^2.3.11", "@formatjs/cli": "^4.2.29", - "@netlify/plugin-nextjs": "^5.15.1", + "@netlify/plugin-nextjs": "^5.15.5", "@rollup/plugin-alias": "^5.0.0", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-json": "^6.0.0", @@ -137,8 +137,8 @@ "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.3.0", "@types/jest": "^30.0.0", - "@types/node": "^24.9.2", - "@types/react": "^19.2.7", + "@types/node": "^24.10.8", + "@types/react": "^19.2.8", "@types/react-dom": "^19.2.2", "@types/react-window": "^1.8.8", "babel-plugin-react-compiler": "19.1.0-rc.2", @@ -153,9 +153,9 @@ "postcss-import": "^15.1.0", "postcss-preset-env": "7.8.3", "prompts": "2.4.2", - "rollup": "^4.52.5", + "rollup": "^4.55.1", "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-delete": "^3.0.1", + "rollup-plugin-delete": "^3.0.2", "rollup-plugin-dts": "^6.3.0", "rollup-plugin-node-externals": "^8.1.1", "rollup-plugin-peer-deps-external": "^2.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4badb24e..d8fe45f8a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@clickhouse/client': - specifier: ^1.12.0 - version: 1.14.0 + specifier: ^1.16.0 + version: 1.16.0 '@date-fns/utc': specifier: ^1.2.0 version: 1.2.0 @@ -25,28 +25,28 @@ importers: version: 5.2.8 '@hello-pangea/dnd': specifier: ^17.0.0 - version: 17.0.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 17.0.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@prisma/adapter-pg': - specifier: ^7.1.0 - version: 7.1.0 + specifier: ^7.2.0 + version: 7.2.0 '@prisma/client': - specifier: ^7.1.0 - version: 7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3) + specifier: ^7.2.0 + version: 7.2.0(prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3) '@prisma/extension-read-replicas': specifier: ^0.5.0 - version: 0.5.0(@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3)) + version: 0.5.0(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)) '@react-spring/web': specifier: ^10.0.3 - version: 10.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 10.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@svgr/cli': specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) '@tanstack/react-query': - specifier: ^5.90.12 - version: 5.90.12(react@19.2.1) + specifier: ^5.90.17 + version: 5.90.17(react@19.2.3) '@umami/react-zen': specifier: ^0.216.0 - version: 0.216.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1)) + version: 0.216.0(@babel/core@7.28.3)(@types/react@19.2.8)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.3)) '@umami/redis-client': specifier: ^0.30.0 version: 0.30.0 @@ -96,8 +96,8 @@ importers: specifier: ^0.25.11 version: 0.25.12 fs-extra: - specifier: ^11.3.2 - version: 11.3.2 + specifier: ^11.3.3 + version: 11.3.3 immer: specifier: ^10.2.0 version: 10.2.0 @@ -127,13 +127,13 @@ importers: version: 2.2.4 lucide-react: specifier: ^0.543.0 - version: 0.543.0(react@19.2.1) + version: 0.543.0(react@19.2.3) maxmind: - specifier: ^5.0.0 - version: 5.0.1 + specifier: ^5.0.3 + version: 5.0.3 next: - specifier: ^15.5.7 - version: 15.5.7(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: ^15.5.9 + version: 15.5.9(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) node-fetch: specifier: ^3.2.8 version: 3.3.2 @@ -144,35 +144,35 @@ importers: specifier: ^5.5.3 version: 5.5.3 pg: - specifier: ^8.16.3 - version: 8.16.3 + specifier: ^8.17.0 + version: 8.17.0 prisma: - specifier: ^7.1.0 - version: 7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3) + specifier: ^7.2.0 + version: 7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) pure-rand: specifier: ^7.0.1 version: 7.0.1 react: - specifier: ^19.2.1 - version: 19.2.1 + specifier: ^19.2.3 + version: 19.2.3 react-dom: - specifier: ^19.2.1 - version: 19.2.1(react@19.2.1) + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) react-error-boundary: specifier: ^4.0.4 - version: 4.1.2(react@19.2.1) + version: 4.1.2(react@19.2.3) react-intl: specifier: ^7.1.14 - version: 7.1.14(react@19.2.1)(typescript@5.9.3) + version: 7.1.14(react@19.2.3)(typescript@5.9.3) react-simple-maps: specifier: ^2.3.0 - version: 2.3.0(prop-types@15.8.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 2.3.0(prop-types@15.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-use-measure: specifier: ^2.0.4 - version: 2.1.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 2.1.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-window: specifier: ^1.8.6 - version: 1.8.11(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + version: 1.8.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3) request-ip: specifier: ^3.3.0 version: 3.3.0 @@ -186,60 +186,60 @@ importers: specifier: ^1.3.4 version: 1.3.4 ua-parser-js: - specifier: ^2.0.6 - version: 2.0.6 + specifier: ^2.0.8 + version: 2.0.8 uuid: specifier: ^13.0.0 version: 13.0.0 zod: - specifier: ^4.1.13 - version: 4.1.13 + specifier: ^4.3.5 + version: 4.3.5 zustand: - specifier: ^5.0.9 - version: 5.0.9(@types/react@19.2.7)(immer@10.2.0)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)) + specifier: ^5.0.10 + version: 5.0.10(@types/react@19.2.8)(immer@10.2.0)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) devDependencies: '@biomejs/biome': - specifier: ^2.3.8 - version: 2.3.8 + specifier: ^2.3.11 + version: 2.3.11 '@formatjs/cli': specifier: ^4.2.29 - version: 4.8.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + version: 4.8.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)) '@netlify/plugin-nextjs': - specifier: ^5.15.1 - version: 5.15.1 + specifier: ^5.15.5 + version: 5.15.5 '@rollup/plugin-alias': specifier: ^5.0.0 - version: 5.1.1(rollup@4.53.3) + version: 5.1.1(rollup@4.55.1) '@rollup/plugin-commonjs': specifier: ^25.0.4 - version: 25.0.8(rollup@4.53.3) + version: 25.0.8(rollup@4.55.1) '@rollup/plugin-json': specifier: ^6.0.0 - version: 6.1.0(rollup@4.53.3) + version: 6.1.0(rollup@4.55.1) '@rollup/plugin-node-resolve': specifier: ^15.2.0 - version: 15.3.1(rollup@4.53.3) + version: 15.3.1(rollup@4.55.1) '@rollup/plugin-replace': specifier: ^5.0.2 - version: 5.0.7(rollup@4.53.3) + version: 5.0.7(rollup@4.55.1) '@rollup/plugin-terser': specifier: ^0.4.4 - version: 0.4.4(rollup@4.53.3) + version: 0.4.4(rollup@4.55.1) '@rollup/plugin-typescript': specifier: ^12.3.0 - version: 12.3.0(rollup@4.53.3)(tslib@2.8.1)(typescript@5.9.3) + version: 12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3) '@types/jest': specifier: ^30.0.0 version: 30.0.0 '@types/node': - specifier: ^24.9.2 - version: 24.10.1 + specifier: ^24.10.8 + version: 24.10.8 '@types/react': - specifier: ^19.2.7 - version: 19.2.7 + specifier: ^19.2.8 + version: 19.2.8 '@types/react-dom': specifier: ^19.2.2 - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.8) '@types/react-window': specifier: ^1.8.8 version: 1.8.8 @@ -254,13 +254,13 @@ importers: version: 13.17.0 extract-react-intl-messages: specifier: ^4.1.1 - version: 4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + version: 4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)) husky: specifier: ^9.1.7 version: 9.1.7 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + version: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) lint-staged: specifier: ^16.2.6 version: 16.2.7 @@ -280,26 +280,26 @@ importers: specifier: 2.4.2 version: 2.4.2 rollup: - specifier: ^4.52.5 - version: 4.53.3 + specifier: ^4.55.1 + version: 4.55.1 rollup-plugin-copy: specifier: ^3.4.0 version: 3.5.0 rollup-plugin-delete: - specifier: ^3.0.1 - version: 3.0.1(rollup@4.53.3) + specifier: ^3.0.2 + version: 3.0.2(rollup@4.55.1) rollup-plugin-dts: specifier: ^6.3.0 - version: 6.3.0(rollup@4.53.3)(typescript@5.9.3) + version: 6.3.0(rollup@4.55.1)(typescript@5.9.3) rollup-plugin-node-externals: specifier: ^8.1.1 - version: 8.1.2(rollup@4.53.3) + version: 8.1.2(rollup@4.55.1) rollup-plugin-peer-deps-external: specifier: ^2.2.4 - version: 2.2.4(rollup@4.53.3) + version: 2.2.4(rollup@4.55.1) rollup-plugin-postcss: specifier: ^4.0.2 - version: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + version: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) stylelint: specifier: ^15.10.1 version: 15.11.0(typescript@5.9.3) @@ -317,10 +317,10 @@ importers: version: 6.2.1 ts-jest: specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) + version: 10.9.2(@types/node@24.10.8)(typescript@5.9.3) tsup: specifier: ^8.5.0 version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) @@ -508,55 +508,55 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@biomejs/biome@2.3.8': - resolution: {integrity: sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==} + '@biomejs/biome@2.3.11': + resolution: {integrity: sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.3.8': - resolution: {integrity: sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==} + '@biomejs/cli-darwin-arm64@2.3.11': + resolution: {integrity: sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.3.8': - resolution: {integrity: sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==} + '@biomejs/cli-darwin-x64@2.3.11': + resolution: {integrity: sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.3.8': - resolution: {integrity: sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==} + '@biomejs/cli-linux-arm64-musl@2.3.11': + resolution: {integrity: sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.3.8': - resolution: {integrity: sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==} + '@biomejs/cli-linux-arm64@2.3.11': + resolution: {integrity: sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.3.8': - resolution: {integrity: sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==} + '@biomejs/cli-linux-x64-musl@2.3.11': + resolution: {integrity: sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.3.8': - resolution: {integrity: sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==} + '@biomejs/cli-linux-x64@2.3.11': + resolution: {integrity: sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.3.8': - resolution: {integrity: sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==} + '@biomejs/cli-win32-arm64@2.3.11': + resolution: {integrity: sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.3.8': - resolution: {integrity: sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==} + '@biomejs/cli-win32-x64@2.3.11': + resolution: {integrity: sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -573,11 +573,11 @@ packages: '@chevrotain/utils@10.5.0': resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} - '@clickhouse/client-common@1.14.0': - resolution: {integrity: sha512-CyUcv2iCkZ1A++vmOSufYRpHR3aAWVfbrWed7ATzf0yyx/BW/2SEqlL07vBpSRa3BIkQe/DSOHVv8JkWZpUOwQ==} + '@clickhouse/client-common@1.16.0': + resolution: {integrity: sha512-qMzkI1NmV29ZjFkNpVSvGNfA0c7sCExlufAQMv+V+5xtNeYXnRfdqzmBLIQoq6Pf1ij0kw/wGLD3HQrl7pTFLA==} - '@clickhouse/client@1.14.0': - resolution: {integrity: sha512-co2spjR7wZoZ3Ck0H/jv76bpiuO3oJHtOmq9/gxFiod2DcT9NFg01u/hXcG8MJFnEJuMB6e3vGqS6IOnLwHqRw==} + '@clickhouse/client@1.16.0': + resolution: {integrity: sha512-ThPhoRMsKsf/hmBEgWlUsGxFecsr3i+k3JI8JV0Od7UpH2BSmk9VKMGJoyPCrTL0vPUs5rJH+7o4iCqBF09Xvg==} engines: {node: '>=16'} '@colors/colors@1.5.0': @@ -915,11 +915,8 @@ packages: '@electric-sql/pglite@0.3.2': resolution: {integrity: sha512-zfWWa+V2ViDCY/cmUfRqeWY1yLto+EpxjXnZzenB1TyxsTiXaTWeZFIZw6mac52BsuQm0RjCnisjBtdBaXOI6w==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -1322,75 +1319,38 @@ packages: resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - '@img/sharp-darwin-arm64@0.34.5': resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - '@img/sharp-darwin-x64@0.34.5': resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} - cpu: [arm64] - os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} - cpu: [x64] - os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} - cpu: [arm64] - os: [linux] - '@img/sharp-libvips-linux-arm64@1.2.4': resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} - cpu: [arm] - os: [linux] - '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} - cpu: [ppc64] - os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] @@ -1401,76 +1361,38 @@ packages: cpu: [riscv64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} - cpu: [s390x] - os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} - cpu: [x64] - os: [linux] - '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} - cpu: [arm64] - os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} - cpu: [x64] - os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -1483,94 +1405,47 @@ packages: cpu: [riscv64] os: [linux] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - '@img/sharp-win32-arm64@0.34.5': resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - '@img/sharp-win32-ia32@0.34.5': resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - '@img/sharp-win32-x64@0.34.5': resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -1725,15 +1600,15 @@ packages: resolution: {integrity: sha512-JwqeCQ1U3fvccttHZq7Tk0m/TMC6WcFAQZdukypW3AzlJYKYTGNVd1ANU2GuhKnv4UQuOFj3oAl0LLG/gxFN1w==} engines: {node: '>=16'} - '@netlify/plugin-nextjs@5.15.1': - resolution: {integrity: sha512-HXm94tteOuA0FYwhkxjYIPe0zta+Dsu0wz7LnhfqVlaYcRaOLjHtd2vgfmpz3np/fx9TQg3gCfqGkXt2a9i7Aw==} + '@netlify/plugin-nextjs@5.15.5': + resolution: {integrity: sha512-Lvix59vHCEfvopILvdfIK2EPe/CrLH5qrIdwYnJbxpp/SSVgklsHpBrfNM9ADTr310r+WJRDz11NcDyHu3iT9w==} engines: {node: '>=18.0.0'} - '@next/env@15.5.7': - resolution: {integrity: sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==} + '@next/env@15.5.9': + resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==} - '@next/env@16.0.7': - resolution: {integrity: sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==} + '@next/env@16.1.1': + resolution: {integrity: sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==} '@next/swc-darwin-arm64@15.5.7': resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} @@ -1741,8 +1616,8 @@ packages: cpu: [arm64] os: [darwin] - '@next/swc-darwin-arm64@16.0.7': - resolution: {integrity: sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==} + '@next/swc-darwin-arm64@16.1.1': + resolution: {integrity: sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1753,8 +1628,8 @@ packages: cpu: [x64] os: [darwin] - '@next/swc-darwin-x64@16.0.7': - resolution: {integrity: sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==} + '@next/swc-darwin-x64@16.1.1': + resolution: {integrity: sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1765,8 +1640,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-gnu@16.0.7': - resolution: {integrity: sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==} + '@next/swc-linux-arm64-gnu@16.1.1': + resolution: {integrity: sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1777,8 +1652,8 @@ packages: cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.0.7': - resolution: {integrity: sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==} + '@next/swc-linux-arm64-musl@16.1.1': + resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1789,8 +1664,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-gnu@16.0.7': - resolution: {integrity: sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==} + '@next/swc-linux-x64-gnu@16.1.1': + resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1801,8 +1676,8 @@ packages: cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.0.7': - resolution: {integrity: sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==} + '@next/swc-linux-x64-musl@16.1.1': + resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1813,8 +1688,8 @@ packages: cpu: [arm64] os: [win32] - '@next/swc-win32-arm64-msvc@16.0.7': - resolution: {integrity: sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==} + '@next/swc-win32-arm64-msvc@16.1.1': + resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1825,8 +1700,8 @@ packages: cpu: [x64] os: [win32] - '@next/swc-win32-x64-msvc@16.0.7': - resolution: {integrity: sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==} + '@next/swc-win32-x64-msvc@16.1.1': + resolution: {integrity: sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1847,14 +1722,14 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@prisma/adapter-pg@7.1.0': - resolution: {integrity: sha512-DSAnUwkKfX4bUzhkrjGN4IBQzwg0nvFw2W17H0Oa532I5w9nLtTJ9mAEGDs1nUBEGRAsa0c7qsf8CSgfJ4DsBQ==} + '@prisma/adapter-pg@7.2.0': + resolution: {integrity: sha512-euIdQ13cRB2wZ3jPsnDnFhINquo1PYFPCg6yVL8b2rp3EdinQHsX9EDdCtRr489D5uhphcRk463OdQAFlsCr0w==} - '@prisma/client-runtime-utils@7.1.0': - resolution: {integrity: sha512-39xmeBrNTN40FzF34aJMjfX1PowVCqoT3UKUWBBSP3aXV05NRqGBC3x2wCDs96ti6ZgdiVzqnRDHtbzU8X+lPQ==} + '@prisma/client-runtime-utils@7.2.0': + resolution: {integrity: sha512-dn7oB53v0tqkB0wBdMuTNFNPdEbfICEUe82Tn9FoKAhJCUkDH+fmyEp0ClciGh+9Hp2Tuu2K52kth2MTLstvmA==} - '@prisma/client@7.1.0': - resolution: {integrity: sha512-qf7GPYHmS/xybNiSOpzv9wBo+UwqfL2PeyX+08v+KVHDI0AlSCQIh5bBySkH3alu06NX9wy98JEnckhMHoMFfA==} + '@prisma/client@7.2.0': + resolution: {integrity: sha512-JdLF8lWZ+LjKGKpBqyAlenxd/kXjd1Abf/xK+6vUA7R7L2Suo6AFTHFRpPSdAKCan9wzdFApsUpSa/F6+t1AtA==} engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' @@ -1865,46 +1740,46 @@ packages: typescript: optional: true - '@prisma/config@7.1.0': - resolution: {integrity: sha512-Uz+I43Wn1RYNHtuYtOhOnUcNMWp2Pd3GUDDKs37xlHptCGpzEG3MRR9L+8Y2ISMsMI24z/Ni+ww6OB/OO8M0sQ==} + '@prisma/config@7.2.0': + resolution: {integrity: sha512-qmvSnfQ6l/srBW1S7RZGfjTQhc44Yl3ldvU6y3pgmuLM+83SBDs6UQVgMtQuMRe9J3gGqB0RF8wER6RlXEr6jQ==} '@prisma/debug@6.8.2': resolution: {integrity: sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==} - '@prisma/debug@7.1.0': - resolution: {integrity: sha512-pPAckG6etgAsEBusmZiFwM9bldLSNkn++YuC4jCTJACdK5hLOVnOzX7eSL2FgaU6Gomd6wIw21snUX2dYroMZQ==} + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} - '@prisma/dev@0.15.0': - resolution: {integrity: sha512-KhWaipnFlS/fWEs6I6Oqjcy2S08vKGmxJ5LexqUl/3Ve0EgLUsZwdKF0MvqPM5F5ttw8GtfZarjM5y7VLwv9Ow==} + '@prisma/dev@0.17.0': + resolution: {integrity: sha512-6sGebe5jxX+FEsQTpjHLzvOGPn6ypFQprcs3jcuIWv1Xp/5v6P/rjfdvAwTkP2iF6pDx2tCd8vGLNWcsWzImTA==} - '@prisma/driver-adapter-utils@7.1.0': - resolution: {integrity: sha512-AlVLzeXkw81+47MvQ9M8DvTiHkRfJ8xzklTbYjpskb0cTTDVHboTI/OVwT6Wcep/bNvfLKJYO0nylBiM5rxgww==} + '@prisma/driver-adapter-utils@7.2.0': + resolution: {integrity: sha512-gzrUcbI9VmHS24Uf+0+7DNzdIw7keglJsD5m/MHxQOU68OhGVzlphQRobLiDMn8CHNA2XN8uugwKjudVtnfMVQ==} - '@prisma/engines-version@7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba': - resolution: {integrity: sha512-qZUevUh+yPhGT28rDQnV8V2kLnFjirzhVD67elRPIJHRsUV/mkII10HSrJrhK/U2GYgAxXR2VEREtq7AsfS8qw==} + '@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3': + resolution: {integrity: sha512-KezsjCZDsbjNR7SzIiVlUsn9PnLePI7r5uxABlwL+xoerurZTfgQVbIjvjF2sVr3Uc0ZcsnREw3F84HvbggGdA==} - '@prisma/engines@7.1.0': - resolution: {integrity: sha512-KQlraOybdHAzVv45KWKJzpR9mJLkib7/TyApQpqrsL7FUHfgjIcy8jrVGt3iNfG6/GDDl+LNlJ84JSQwIfdzxA==} + '@prisma/engines@7.2.0': + resolution: {integrity: sha512-HUeOI/SvCDsHrR9QZn24cxxZcujOjcS3w1oW/XVhnSATAli5SRMOfp/WkG3TtT5rCxDA4xOnlJkW7xkho4nURA==} '@prisma/extension-read-replicas@0.5.0': resolution: {integrity: sha512-t0kLjqFMte4wwGrZFhya4iFoyoOY4kjlyyE60WXZL66PqP6PcBpW/35eKb/3UcxgjJxcDlaJKfmGokFLOyafiQ==} peerDependencies: '@prisma/client': ^7.0.0 - '@prisma/fetch-engine@7.1.0': - resolution: {integrity: sha512-GZYF5Q8kweXWGfn87hTu17kw7x1DgnehgKoE4Zg1BmHYF3y1Uu0QRY/qtSE4veH3g+LW8f9HKqA0tARG66bxxQ==} + '@prisma/fetch-engine@7.2.0': + resolution: {integrity: sha512-Z5XZztJ8Ap+wovpjPD2lQKnB8nWFGNouCrglaNFjxIWAGWz0oeHXwUJRiclIoSSXN/ptcs9/behptSk8d0Yy6w==} '@prisma/get-platform@6.8.2': resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==} - '@prisma/get-platform@7.1.0': - resolution: {integrity: sha512-lq8hMdjKiZftuT5SssYB3EtQj8+YjL24/ZTLflQqzFquArKxBcyp6Xrblto+4lzIKJqnpOjfMiBjMvl7YuD7+Q==} + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} '@prisma/query-plan-executor@6.18.0': resolution: {integrity: sha512-jZ8cfzFgL0jReE1R10gT8JLHtQxjWYLiQ//wHmVYZ2rVkFHoh0DT8IXsxcKcFlfKN7ak7k6j0XMNn2xVNyr5cA==} - '@prisma/studio-core@0.8.2': - resolution: {integrity: sha512-/iAEWEUpTja+7gVMu1LtR2pPlvDmveAwMHdTWbDeGlT7yiv0ZTCPpmeAGdq/Y9aJ9Zj1cEGBXGRbmmNPj022PQ==} + '@prisma/studio-core@0.9.0': + resolution: {integrity: sha512-xA2zoR/ADu/NCSQuriBKTh6Ps4XjU0bErkEcgMfnSGh346K1VI7iWKnoq1l2DoxUqiddPHIEWwtxJ6xCHG6W7g==} peerDependencies: '@types/react': ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0 @@ -2655,113 +2530,128 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} cpu: [x64] os: [win32] @@ -2781,8 +2671,8 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} @@ -2872,14 +2762,14 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/helpers@0.5.17': - resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} - '@tanstack/query-core@5.90.12': - resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} + '@tanstack/query-core@5.90.17': + resolution: {integrity: sha512-hDww+RyyYhjhUfoYQ4es6pbgxY7LNiPWxt4l1nJqhByjndxJ7HIjDxTBtfvMr5HwjYavMrd+ids5g4Rfev3lVQ==} - '@tanstack/react-query@5.90.12': - resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==} + '@tanstack/react-query@5.90.17': + resolution: {integrity: sha512-PGc2u9KLwohDUSchjW9MZqeDQJfJDON7y4W7REdNBgiFKxQy+Pf7eGjiFWEj5xPqKzAeHYdAb62IWI1a9UJyGQ==} peerDependencies: react: ^18 || ^19 @@ -2963,8 +2853,8 @@ packages: '@types/node@14.18.63': resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - '@types/node@24.10.1': - resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} + '@types/node@24.10.8': + resolution: {integrity: sha512-r0bBaXu5Swb05doFYO2kTWHMovJnNVbCsII0fhesM8bNRlLhXIuckley4a2DaD+vOdmm5G+zGkQZAPZsF80+YQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2977,8 +2867,8 @@ packages: '@types/react-window@1.8.8': resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==} - '@types/react@19.2.7': - resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + '@types/react@19.2.8': + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -3229,6 +3119,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.9.14: + resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} + hasBin: true + bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} @@ -3339,11 +3233,8 @@ packages: caniuse-lite@1.0.30001735: resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==} - caniuse-lite@1.0.30001741: - resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} - - caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} + caniuse-lite@1.0.30001764: + resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -3465,13 +3356,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} @@ -3818,8 +3702,8 @@ packages: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} - del@8.0.0: - resolution: {integrity: sha512-R6ep6JJ+eOBZsBr9esiNN1gxFbZE4Q2cULkUSFumGYecAiS6qodDvcPx/sFuWHMNul7DWmrtoEOpYSm7o6tbSA==} + del@8.0.1: + resolution: {integrity: sha512-gPqh0mKTPvaUZGAuHbrBUYKZWBNAeHG7TU3QH5EhVwPMyKvmfJaNXhcD2jTcXsJRRcffuho4vaYweu80dRrMGA==} engines: {node: '>=18'} delayed-stream@1.0.0: @@ -3843,10 +3727,6 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -4171,8 +4051,8 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.2: - resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} engines: {node: '>=14.14'} fs-extra@8.1.0: @@ -4520,9 +4400,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -5206,8 +5083,8 @@ packages: mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} - maxmind@5.0.1: - resolution: {integrity: sha512-hYxQxvHkBUlyF34f7IlQOb60rytezCi2oZ8H/BtZpcoodXTlcK1eLgf7kY2TofHqBC3o+Hqtvde9kS72gFQSDw==} + maxmind@5.0.3: + resolution: {integrity: sha512-oMtZwLrsp0LcZehfYKIirtwKMBycMMqMA1/Dc9/BlUqIEtXO75mIzMJ3PYCV1Ji+BpoUCk+lTzRfh9c+ptGdyQ==} engines: {node: '>=12', npm: '>=6'} mdn-data@2.0.14: @@ -5357,8 +5234,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@15.5.7: - resolution: {integrity: sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==} + next@15.5.9: + resolution: {integrity: sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -5378,8 +5255,8 @@ packages: sass: optional: true - next@16.0.7: - resolution: {integrity: sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==} + next@16.1.1: + resolution: {integrity: sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -5520,8 +5397,8 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} - p-map@7.0.3: - resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} p-queue@6.6.2: @@ -5608,30 +5485,30 @@ packages: performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - pg-cloudflare@1.2.7: - resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - pg-connection-string@2.9.1: - resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + pg-connection-string@2.10.0: + resolution: {integrity: sha512-ur/eoPKzDx2IjPaYyXS6Y8NSblxM7X64deV2ObV57vhjsWiwLvUD6meukAzogiOsu60GO8m/3Cb6FdJsWNjwXg==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.10.1: - resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} + pg-pool@3.11.0: + resolution: {integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==} peerDependencies: pg: '>=8.0' - pg-protocol@1.10.3: - resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} + pg-protocol@1.11.0: + resolution: {integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.16.3: - resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} + pg@8.17.0: + resolution: {integrity: sha512-SRl6PbO7zqhD5bZ6lVtEFWknVeWv6Eab+PKzowWTEAce5MFiHTcSdi2N9M9m7VYAv1Hc3OOCxSka3hPBYoXHJA==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -6149,6 +6026,10 @@ packages: resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} engines: {node: '>=12'} + presentable-error@0.0.1: + resolution: {integrity: sha512-E6rsNU1QNJgB3sjj7OANinGncFKuK+164sLXw1/CqBjj/EkXSoSdHCtWQGBNlREIGLnL7IEUEGa08YFVUbrhVg==} + engines: {node: '>=16'} + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -6166,8 +6047,8 @@ packages: resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - prisma@7.1.0: - resolution: {integrity: sha512-dy/3urE4JjhdiW5b09pGjVhGI7kPESK2VlCDrCqeYK5m5SslAtG5FCGnZWP7E8Sdg+Ow1wV2mhJH5RTFL5gEsw==} + prisma@7.2.0: + resolution: {integrity: sha512-jSdHWgWOgFF24+nRyyNRVBIgGDQEsMEF8KPHvhBBg3jWyR9fUAK0Nq9ThUmiGlNgq2FA7vSk/ZoCvefod+a8qg==} engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true peerDependencies: @@ -6252,10 +6133,10 @@ packages: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-dom@19.2.1: - resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} peerDependencies: - react: ^19.2.1 + react: ^19.2.3 react-error-boundary@4.1.2: resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} @@ -6328,8 +6209,8 @@ packages: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react@19.2.1: - resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} read-babelrc-up@1.1.0: @@ -6460,8 +6341,8 @@ packages: resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} engines: {node: '>=8.3'} - rollup-plugin-delete@3.0.1: - resolution: {integrity: sha512-4tyijMQFwSDLA04DAHwbI2TrRwPiRwAqBQ17dxyr9CgHeHXLdgk8IDVWHFWPrL3UZJWrAmHohQ2MgmVghQDrlg==} + rollup-plugin-delete@3.0.2: + resolution: {integrity: sha512-26GSi/aeYQ/hEBdG1rjEMeh+WUhiPZ3hGmSr9Ucj7mhLQ1P9j8KEgtYoybDp7OlIMj3eQjHHB9fnqhxNuVgfzA==} engines: {node: '>=18'} peerDependencies: rollup: '*' @@ -6493,8 +6374,8 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -6573,10 +6454,6 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -6624,9 +6501,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -7120,8 +6994,8 @@ packages: ua-is-frozen@0.1.2: resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==} - ua-parser-js@2.0.6: - resolution: {integrity: sha512-EmaxXfltJaDW75SokrY4/lXMrVyXomE/0FpIIqP2Ctic93gK7rlme55Cwkz8l3YZ6gqf94fCU7AnIkidd/KXPg==} + ua-parser-js@2.0.8: + resolution: {integrity: sha512-BdnBM5waFormdrOFBU+cA90R689V0tWUWlIG2i30UXxElHjuCu5+dOV2Etw3547jcQ/yaLtPm9wrqIuOY2bSJg==} hasBin: true ufo@1.6.1: @@ -7346,11 +7220,11 @@ packages: zeptomatch@2.0.2: resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==} - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zod@4.3.5: + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} - zustand@5.0.9: - resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} + zustand@5.0.10: + resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=18.0.0' @@ -7565,39 +7439,39 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@biomejs/biome@2.3.8': + '@biomejs/biome@2.3.11': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.3.8 - '@biomejs/cli-darwin-x64': 2.3.8 - '@biomejs/cli-linux-arm64': 2.3.8 - '@biomejs/cli-linux-arm64-musl': 2.3.8 - '@biomejs/cli-linux-x64': 2.3.8 - '@biomejs/cli-linux-x64-musl': 2.3.8 - '@biomejs/cli-win32-arm64': 2.3.8 - '@biomejs/cli-win32-x64': 2.3.8 + '@biomejs/cli-darwin-arm64': 2.3.11 + '@biomejs/cli-darwin-x64': 2.3.11 + '@biomejs/cli-linux-arm64': 2.3.11 + '@biomejs/cli-linux-arm64-musl': 2.3.11 + '@biomejs/cli-linux-x64': 2.3.11 + '@biomejs/cli-linux-x64-musl': 2.3.11 + '@biomejs/cli-win32-arm64': 2.3.11 + '@biomejs/cli-win32-x64': 2.3.11 - '@biomejs/cli-darwin-arm64@2.3.8': + '@biomejs/cli-darwin-arm64@2.3.11': optional: true - '@biomejs/cli-darwin-x64@2.3.8': + '@biomejs/cli-darwin-x64@2.3.11': optional: true - '@biomejs/cli-linux-arm64-musl@2.3.8': + '@biomejs/cli-linux-arm64-musl@2.3.11': optional: true - '@biomejs/cli-linux-arm64@2.3.8': + '@biomejs/cli-linux-arm64@2.3.11': optional: true - '@biomejs/cli-linux-x64-musl@2.3.8': + '@biomejs/cli-linux-x64-musl@2.3.11': optional: true - '@biomejs/cli-linux-x64@2.3.8': + '@biomejs/cli-linux-x64@2.3.11': optional: true - '@biomejs/cli-win32-arm64@2.3.8': + '@biomejs/cli-win32-arm64@2.3.11': optional: true - '@biomejs/cli-win32-x64@2.3.8': + '@biomejs/cli-win32-x64@2.3.11': optional: true '@chevrotain/cst-dts-gen@10.5.0': @@ -7615,11 +7489,11 @@ snapshots: '@chevrotain/utils@10.5.0': {} - '@clickhouse/client-common@1.14.0': {} + '@clickhouse/client-common@1.16.0': {} - '@clickhouse/client@1.14.0': + '@clickhouse/client@1.16.0': dependencies: - '@clickhouse/client-common': 1.14.0 + '@clickhouse/client-common': 1.16.0 '@colors/colors@1.5.0': optional: true @@ -7919,12 +7793,7 @@ snapshots: '@electric-sql/pglite@0.3.2': {} - '@emnapi/runtime@1.5.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -8091,10 +7960,10 @@ snapshots: '@fontsource/jetbrains-mono@5.2.8': {} - '@formatjs/cli@4.8.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3))': + '@formatjs/cli@4.8.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3))': dependencies: '@formatjs/icu-messageformat-parser': 2.1.0 - '@formatjs/ts-transformer': 3.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + '@formatjs/ts-transformer': 3.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)) '@types/estree': 0.0.50 '@types/fs-extra': 9.0.13 '@types/json-stable-stringify': 1.2.0 @@ -8181,15 +8050,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@formatjs/ts-transformer@2.13.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3))': + '@formatjs/ts-transformer@2.13.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3))': dependencies: intl-messageformat-parser: 6.1.2 tslib: 2.8.1 typescript: 4.9.5 optionalDependencies: - ts-jest: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + ts-jest: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3) - '@formatjs/ts-transformer@3.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3))': + '@formatjs/ts-transformer@3.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3))': dependencies: '@formatjs/icu-messageformat-parser': 2.1.0 '@types/node': 14.18.63 @@ -8197,19 +8066,19 @@ snapshots: tslib: 2.8.1 typescript: 4.9.5 optionalDependencies: - ts-jest: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3) + ts-jest: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3) - '@hello-pangea/dnd@17.0.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@hello-pangea/dnd@17.0.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@babel/runtime': 7.28.3 css-box-model: 1.2.1 memoize-one: 6.0.0 raf-schd: 4.0.3 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - react-redux: 9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-redux: 9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1) redux: 5.0.1 - use-memo-one: 1.1.3(react@19.2.1) + use-memo-one: 1.1.3(react@19.2.3) transitivePeerDependencies: - '@types/react' @@ -8220,108 +8089,56 @@ snapshots: '@img/colour@1.0.0': optional: true - '@img/sharp-darwin-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 - optional: true - '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 - optional: true - '@img/sharp-darwin-x64@0.34.5': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': - optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': - optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': - optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': - optional: true - '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': - optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': - optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': - optional: true - '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 - optional: true - '@img/sharp-linux-arm64@0.34.5': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 - optional: true - '@img/sharp-linux-arm@0.34.5': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-ppc64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 - optional: true - '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: '@img/sharp-libvips-linux-ppc64': 1.2.4 @@ -8332,90 +8149,56 @@ snapshots: '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 - optional: true - '@img/sharp-linux-s390x@0.34.5': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 - optional: true - '@img/sharp-linux-x64@0.34.5': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - optional: true - '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.34.3': - dependencies: - '@emnapi/runtime': 1.5.0 - optional: true - '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.7.1 - optional: true - - '@img/sharp-win32-arm64@0.34.3': + '@emnapi/runtime': 1.8.1 optional: true '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.34.3': - optional: true - '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.34.3': - optional: true - '@img/sharp-win32-x64@0.34.5': optional: true '@internationalized/date@3.10.0': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 '@internationalized/message@3.1.8': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 intl-messageformat: 10.7.18 '@internationalized/number@3.6.5': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 '@internationalized/string@3.2.7': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 '@isaacs/balanced-match@4.0.1': {} @@ -8445,27 +8228,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -8492,7 +8275,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -8514,7 +8297,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -8532,7 +8315,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-regex-util: 30.0.1 '@jest/reporters@29.7.0': @@ -8543,7 +8326,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.30 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -8617,7 +8400,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 24.10.1 + '@types/node': 24.10.8 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8627,7 +8410,7 @@ snapshots: '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 24.10.1 + '@types/node': 24.10.8 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8662,58 +8445,58 @@ snapshots: chevrotain: 10.5.0 lilconfig: 2.1.0 - '@netlify/plugin-nextjs@5.15.1': {} + '@netlify/plugin-nextjs@5.15.5': {} - '@next/env@15.5.7': {} + '@next/env@15.5.9': {} - '@next/env@16.0.7': {} + '@next/env@16.1.1': {} '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-arm64@16.0.7': + '@next/swc-darwin-arm64@16.1.1': optional: true '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-darwin-x64@16.0.7': + '@next/swc-darwin-x64@16.1.1': optional: true '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@16.0.7': + '@next/swc-linux-arm64-gnu@16.1.1': optional: true '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-arm64-musl@16.0.7': + '@next/swc-linux-arm64-musl@16.1.1': optional: true '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-gnu@16.0.7': + '@next/swc-linux-x64-gnu@16.1.1': optional: true '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-linux-x64-musl@16.0.7': + '@next/swc-linux-x64-musl@16.1.1': optional: true '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@16.0.7': + '@next/swc-win32-arm64-msvc@16.1.1': optional: true '@next/swc-win32-x64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@16.0.7': + '@next/swc-win32-x64-msvc@16.1.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -8731,24 +8514,24 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@prisma/adapter-pg@7.1.0': + '@prisma/adapter-pg@7.2.0': dependencies: - '@prisma/driver-adapter-utils': 7.1.0 - pg: 8.16.3 + '@prisma/driver-adapter-utils': 7.2.0 + pg: 8.17.0 postgres-array: 3.0.4 transitivePeerDependencies: - pg-native - '@prisma/client-runtime-utils@7.1.0': {} + '@prisma/client-runtime-utils@7.2.0': {} - '@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@prisma/client-runtime-utils': 7.1.0 + '@prisma/client-runtime-utils': 7.2.0 optionalDependencies: - prisma: 7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3) + prisma: 7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) typescript: 5.9.3 - '@prisma/config@7.1.0': + '@prisma/config@7.2.0': dependencies: c12: 3.1.0 deepmerge-ts: 7.1.5 @@ -8759,9 +8542,9 @@ snapshots: '@prisma/debug@6.8.2': {} - '@prisma/debug@7.1.0': {} + '@prisma/debug@7.2.0': {} - '@prisma/dev@0.15.0(typescript@5.9.3)': + '@prisma/dev@0.17.0(typescript@5.9.3)': dependencies: '@electric-sql/pglite': 0.3.2 '@electric-sql/pglite-socket': 0.0.6(@electric-sql/pglite@0.3.2) @@ -8783,1149 +8566,1149 @@ snapshots: transitivePeerDependencies: - typescript - '@prisma/driver-adapter-utils@7.1.0': + '@prisma/driver-adapter-utils@7.2.0': dependencies: - '@prisma/debug': 7.1.0 + '@prisma/debug': 7.2.0 - '@prisma/engines-version@7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba': {} + '@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3': {} - '@prisma/engines@7.1.0': + '@prisma/engines@7.2.0': dependencies: - '@prisma/debug': 7.1.0 - '@prisma/engines-version': 7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba - '@prisma/fetch-engine': 7.1.0 - '@prisma/get-platform': 7.1.0 + '@prisma/debug': 7.2.0 + '@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3 + '@prisma/fetch-engine': 7.2.0 + '@prisma/get-platform': 7.2.0 - '@prisma/extension-read-replicas@0.5.0(@prisma/client@7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3))': + '@prisma/extension-read-replicas@0.5.0(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))': dependencies: - '@prisma/client': 7.1.0(prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3))(typescript@5.9.3) + '@prisma/client': 7.2.0(prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3) - '@prisma/fetch-engine@7.1.0': + '@prisma/fetch-engine@7.2.0': dependencies: - '@prisma/debug': 7.1.0 - '@prisma/engines-version': 7.1.0-6.ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba - '@prisma/get-platform': 7.1.0 + '@prisma/debug': 7.2.0 + '@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3 + '@prisma/get-platform': 7.2.0 '@prisma/get-platform@6.8.2': dependencies: '@prisma/debug': 6.8.2 - '@prisma/get-platform@7.1.0': + '@prisma/get-platform@7.2.0': dependencies: - '@prisma/debug': 7.1.0 + '@prisma/debug': 7.2.0 '@prisma/query-plan-executor@6.18.0': {} - '@prisma/studio-core@0.8.2(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@prisma/studio-core@0.9.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@types/react': 19.2.7 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@types/react': 19.2.8 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/autocomplete@3.0.0-rc.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/autocomplete@3.0.0-rc.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/combobox': 3.14.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/listbox': 3.15.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/searchfield': 3.8.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/autocomplete': 3.0.0-beta.3(react@19.2.1) - '@react-stately/combobox': 3.12.0(react@19.2.1) - '@react-types/autocomplete': 3.0.0-alpha.35(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/combobox': 3.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/listbox': 3.15.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/searchfield': 3.8.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/autocomplete': 3.0.0-beta.3(react@19.2.3) + '@react-stately/combobox': 3.12.0(react@19.2.3) + '@react-types/autocomplete': 3.0.0-alpha.35(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/breadcrumbs@3.5.29(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/breadcrumbs@3.5.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/link': 3.8.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/breadcrumbs': 3.7.17(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/link': 3.8.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/breadcrumbs': 3.7.17(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/button@3.14.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/button@3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/toolbar': 3.0.0-beta.21(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/toggle': 3.9.2(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/toolbar': 3.0.0-beta.21(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/toggle': 3.9.2(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/calendar@3.9.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/calendar@3.9.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/calendar': 3.9.0(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/calendar': 3.8.0(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/calendar': 3.9.0(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/calendar': 3.8.0(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/checkbox@3.16.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/checkbox@3.16.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/form': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/toggle': 3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/checkbox': 3.7.2(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/toggle': 3.9.2(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/form': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/toggle': 3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/checkbox': 3.7.2(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/toggle': 3.9.2(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/collections@3.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/collections@3.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - use-sync-external-store: 1.6.0(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) - '@react-aria/color@3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/color@3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/numberfield': 3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/slider': 3.8.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/spinbutton': 3.6.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/color': 3.9.2(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-types/color': 3.1.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/numberfield': 3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/slider': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/spinbutton': 3.6.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/color': 3.9.2(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-types/color': 3.1.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/combobox@3.14.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/combobox@3.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/listbox': 3.15.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/listbox': 3.15.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/menu': 3.19.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/combobox': 3.12.0(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/combobox': 3.13.9(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/menu': 3.19.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/combobox': 3.12.0(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/combobox': 3.13.9(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/datepicker@3.15.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/datepicker@3.15.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/form': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/spinbutton': 3.6.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/datepicker': 3.15.2(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/calendar': 3.8.0(react@19.2.1) - '@react-types/datepicker': 3.13.2(react@19.2.1) - '@react-types/dialog': 3.5.22(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/form': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/spinbutton': 3.6.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/datepicker': 3.15.2(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/calendar': 3.8.0(react@19.2.3) + '@react-types/datepicker': 3.13.2(react@19.2.3) + '@react-types/dialog': 3.5.22(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/dialog@3.5.31(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/dialog@3.5.31(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/dialog': 3.5.22(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/dialog': 3.5.22(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/disclosure@3.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/disclosure@3.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/disclosure': 3.0.8(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/disclosure': 3.0.8(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/dnd@3.11.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/dnd@3.11.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@internationalized/string': 3.2.7 - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/dnd': 3.7.1(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/dnd': 3.7.1(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/focus@3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/focus@3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 clsx: 2.1.1 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/form@3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/form@3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/grid@3.14.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/grid@3.14.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/grid': 3.11.6(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/grid': 3.11.6(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/gridlist@3.14.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/gridlist@3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/grid': 3.14.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-stately/tree': 3.9.3(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/grid': 3.14.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-stately/tree': 3.9.3(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/i18n@3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/i18n@3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 '@internationalized/message': 3.1.8 '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/interactions@3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/interactions@3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-stately/flags': 3.1.2 - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/label@3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/label@3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/landmark@3.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/landmark@3.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - use-sync-external-store: 1.6.0(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) - '@react-aria/link@3.8.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/link@3.8.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/link': 3.6.5(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/link': 3.6.5(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/listbox@3.15.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/listbox@3.15.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-types/listbox': 3.7.4(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-types/listbox': 3.7.4(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) '@react-aria/live-announcer@3.4.4': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 - '@react-aria/menu@3.19.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/menu@3.19.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/menu': 3.9.8(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/tree': 3.9.3(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/menu': 3.10.5(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/menu': 3.9.8(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/tree': 3.9.3(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/menu': 3.10.5(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/meter@3.4.27(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/meter@3.4.27(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/progress': 3.4.27(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/meter': 3.4.13(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/progress': 3.4.27(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/meter': 3.4.13(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/numberfield@3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/numberfield@3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/spinbutton': 3.6.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/numberfield': 3.10.2(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/numberfield': 3.8.15(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/spinbutton': 3.6.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/numberfield': 3.10.2(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/numberfield': 3.8.15(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/overlays@3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/overlays@3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/overlays': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/overlays': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/progress@3.4.27(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/progress@3.4.27(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/progress': 3.5.16(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/progress': 3.5.16(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/radio@3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/radio@3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/form': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/radio': 3.11.2(react@19.2.1) - '@react-types/radio': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/form': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/radio': 3.11.2(react@19.2.3) + '@react-types/radio': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/searchfield@3.8.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/searchfield@3.8.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/searchfield': 3.5.16(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/searchfield': 3.6.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/searchfield': 3.5.16(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/searchfield': 3.6.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/select@3.17.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/select@3.17.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/form': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/listbox': 3.15.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/menu': 3.19.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/select': 3.8.0(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/select': 3.11.0(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/form': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/listbox': 3.15.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/menu': 3.19.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/select': 3.8.0(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/select': 3.11.0(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/selection@3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/selection@3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/separator@3.4.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/separator@3.4.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/slider@3.8.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/slider@3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/slider': 3.7.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/slider': 3.8.2(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/slider': 3.7.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/slider': 3.8.2(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/spinbutton@3.6.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/spinbutton@3.6.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/ssr@3.9.10(react@19.2.1)': + '@react-aria/ssr@3.9.10(react@19.2.3)': dependencies: - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-aria/switch@3.7.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/switch@3.7.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/toggle': 3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/toggle': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/switch': 3.5.15(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/toggle': 3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/toggle': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/switch': 3.5.15(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/table@3.17.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/table@3.17.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/grid': 3.14.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/grid': 3.14.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) '@react-stately/flags': 3.1.2 - '@react-stately/table': 3.15.1(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/table': 3.13.4(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-stately/table': 3.15.1(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/table': 3.13.4(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/tabs@3.10.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/tabs@3.10.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/tabs': 3.8.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/tabs': 3.3.19(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/tabs': 3.8.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/tabs': 3.3.19(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/tag@3.7.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/tag@3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/gridlist': 3.14.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/gridlist': 3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/textfield@3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/textfield@3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/form': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/textfield': 3.12.6(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/form': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/textfield': 3.12.6(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/toast@3.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/toast@3.0.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/landmark': 3.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/toast': 3.1.2(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/landmark': 3.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/toast': 3.1.2(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/toggle@3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/toggle@3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/toggle': 3.9.2(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/toggle': 3.9.2(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/toolbar@3.0.0-beta.21(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/toolbar@3.0.0-beta.21(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/tooltip@3.8.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/tooltip@3.8.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/tooltip': 3.5.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/tooltip': 3.4.21(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/tooltip': 3.5.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/tooltip': 3.4.21(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/tree@3.1.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/tree@3.1.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/gridlist': 3.14.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/tree': 3.9.3(react@19.2.1) - '@react-types/button': 3.14.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/gridlist': 3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/tree': 3.9.3(react@19.2.3) + '@react-types/button': 3.14.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/utils@3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/utils@3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/ssr': 3.9.10(react@19.2.1) + '@react-aria/ssr': 3.9.10(react@19.2.3) '@react-stately/flags': 3.1.2 - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 clsx: 2.1.1 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/virtualizer@4.1.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/virtualizer@4.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-aria/visually-hidden@3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-aria/visually-hidden@3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-spring/animated@10.0.3(react@19.2.1)': + '@react-spring/animated@10.0.3(react@19.2.3)': dependencies: - '@react-spring/shared': 10.0.3(react@19.2.1) + '@react-spring/shared': 10.0.3(react@19.2.3) '@react-spring/types': 10.0.3 - react: 19.2.1 + react: 19.2.3 - '@react-spring/animated@9.7.5(react@19.2.1)': + '@react-spring/animated@9.7.5(react@19.2.3)': dependencies: - '@react-spring/shared': 9.7.5(react@19.2.1) + '@react-spring/shared': 9.7.5(react@19.2.3) '@react-spring/types': 9.7.5 - react: 19.2.1 + react: 19.2.3 - '@react-spring/core@10.0.3(react@19.2.1)': + '@react-spring/core@10.0.3(react@19.2.3)': dependencies: - '@react-spring/animated': 10.0.3(react@19.2.1) - '@react-spring/shared': 10.0.3(react@19.2.1) + '@react-spring/animated': 10.0.3(react@19.2.3) + '@react-spring/shared': 10.0.3(react@19.2.3) '@react-spring/types': 10.0.3 - react: 19.2.1 + react: 19.2.3 - '@react-spring/core@9.7.5(react@19.2.1)': + '@react-spring/core@9.7.5(react@19.2.3)': dependencies: - '@react-spring/animated': 9.7.5(react@19.2.1) - '@react-spring/shared': 9.7.5(react@19.2.1) + '@react-spring/animated': 9.7.5(react@19.2.3) + '@react-spring/shared': 9.7.5(react@19.2.3) '@react-spring/types': 9.7.5 - react: 19.2.1 + react: 19.2.3 '@react-spring/rafz@10.0.3': {} '@react-spring/rafz@9.7.5': {} - '@react-spring/shared@10.0.3(react@19.2.1)': + '@react-spring/shared@10.0.3(react@19.2.3)': dependencies: '@react-spring/rafz': 10.0.3 '@react-spring/types': 10.0.3 - react: 19.2.1 + react: 19.2.3 - '@react-spring/shared@9.7.5(react@19.2.1)': + '@react-spring/shared@9.7.5(react@19.2.3)': dependencies: '@react-spring/rafz': 9.7.5 '@react-spring/types': 9.7.5 - react: 19.2.1 + react: 19.2.3 '@react-spring/types@10.0.3': {} '@react-spring/types@9.7.5': {} - '@react-spring/web@10.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-spring/web@10.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-spring/animated': 10.0.3(react@19.2.1) - '@react-spring/core': 10.0.3(react@19.2.1) - '@react-spring/shared': 10.0.3(react@19.2.1) + '@react-spring/animated': 10.0.3(react@19.2.3) + '@react-spring/core': 10.0.3(react@19.2.3) + '@react-spring/shared': 10.0.3(react@19.2.3) '@react-spring/types': 10.0.3 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-spring/web@9.7.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-spring/web@9.7.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-spring/animated': 9.7.5(react@19.2.1) - '@react-spring/core': 9.7.5(react@19.2.1) - '@react-spring/shared': 9.7.5(react@19.2.1) + '@react-spring/animated': 9.7.5(react@19.2.3) + '@react-spring/core': 9.7.5(react@19.2.3) + '@react-spring/shared': 9.7.5(react@19.2.3) '@react-spring/types': 9.7.5 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-stately/autocomplete@3.0.0-beta.3(react@19.2.1)': + '@react-stately/autocomplete@3.0.0-beta.3(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/calendar@3.9.0(react@19.2.1)': + '@react-stately/calendar@3.9.0(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/calendar': 3.8.0(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/calendar': 3.8.0(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/checkbox@3.7.2(react@19.2.1)': + '@react-stately/checkbox@3.7.2(react@19.2.3)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/collections@3.12.8(react@19.2.1)': + '@react-stately/collections@3.12.8(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/color@3.9.2(react@19.2.1)': + '@react-stately/color@3.9.2(react@19.2.3)': dependencies: '@internationalized/number': 3.6.5 '@internationalized/string': 3.2.7 - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/numberfield': 3.10.2(react@19.2.1) - '@react-stately/slider': 3.7.2(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/color': 3.1.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/numberfield': 3.10.2(react@19.2.3) + '@react-stately/slider': 3.7.2(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/color': 3.1.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/combobox@3.12.0(react@19.2.1)': + '@react-stately/combobox@3.12.0(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/combobox': 3.13.9(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/combobox': 3.13.9(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/data@3.14.1(react@19.2.1)': + '@react-stately/data@3.14.1(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/datepicker@3.15.2(react@19.2.1)': + '@react-stately/datepicker@3.15.2(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 '@internationalized/string': 3.2.7 - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/datepicker': 3.13.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/datepicker': 3.13.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/disclosure@3.0.8(react@19.2.1)': + '@react-stately/disclosure@3.0.8(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/dnd@3.7.1(react@19.2.1)': + '@react-stately/dnd@3.7.1(react@19.2.3)': dependencies: - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 '@react-stately/flags@3.1.2': dependencies: - '@swc/helpers': 0.5.17 + '@swc/helpers': 0.5.18 - '@react-stately/form@3.2.2(react@19.2.1)': + '@react-stately/form@3.2.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/grid@3.11.6(react@19.2.1)': + '@react-stately/grid@3.11.6(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/layout@4.5.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-stately/layout@4.5.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/table': 3.15.1(react@19.2.1) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/table': 3.13.4(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/table': 3.15.1(react@19.2.3) + '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/table': 3.13.4(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-stately/list@3.13.1(react@19.2.1)': + '@react-stately/list@3.13.1(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/menu@3.9.8(react@19.2.1)': + '@react-stately/menu@3.9.8(react@19.2.3)': dependencies: - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-types/menu': 3.10.5(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-types/menu': 3.10.5(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/numberfield@3.10.2(react@19.2.1)': + '@react-stately/numberfield@3.10.2(react@19.2.3)': dependencies: '@internationalized/number': 3.6.5 - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/numberfield': 3.8.15(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/numberfield': 3.8.15(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/overlays@3.6.20(react@19.2.1)': + '@react-stately/overlays@3.6.20(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/overlays': 3.9.2(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/overlays': 3.9.2(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/radio@3.11.2(react@19.2.1)': + '@react-stately/radio@3.11.2(react@19.2.3)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/radio': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/radio': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/searchfield@3.5.16(react@19.2.1)': + '@react-stately/searchfield@3.5.16(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/searchfield': 3.6.6(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/searchfield': 3.6.6(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/select@3.8.0(react@19.2.1)': + '@react-stately/select@3.8.0(react@19.2.3)': dependencies: - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/select': 3.11.0(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/select': 3.11.0(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/selection@3.20.6(react@19.2.1)': + '@react-stately/selection@3.20.6(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/slider@3.7.2(react@19.2.1)': + '@react-stately/slider@3.7.2(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/slider': 3.8.2(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/slider': 3.8.2(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/table@3.15.1(react@19.2.1)': + '@react-stately/table@3.15.1(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) + '@react-stately/collections': 3.12.8(react@19.2.3) '@react-stately/flags': 3.1.2 - '@react-stately/grid': 3.11.6(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/table': 3.13.4(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/grid': 3.11.6(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/table': 3.13.4(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/tabs@3.8.6(react@19.2.1)': + '@react-stately/tabs@3.8.6(react@19.2.3)': dependencies: - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/tabs': 3.3.19(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/tabs': 3.3.19(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/toast@3.1.2(react@19.2.1)': + '@react-stately/toast@3.1.2(react@19.2.3)': dependencies: - '@swc/helpers': 0.5.17 - react: 19.2.1 - use-sync-external-store: 1.6.0(react@19.2.1) + '@swc/helpers': 0.5.18 + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) - '@react-stately/toggle@3.9.2(react@19.2.1)': + '@react-stately/toggle@3.9.2(react@19.2.3)': dependencies: - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/checkbox': 3.10.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/checkbox': 3.10.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/tooltip@3.5.8(react@19.2.1)': + '@react-stately/tooltip@3.5.8(react@19.2.3)': dependencies: - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-types/tooltip': 3.4.21(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-types/tooltip': 3.4.21(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/tree@3.9.3(react@19.2.1)': + '@react-stately/tree@3.9.3(react@19.2.3)': dependencies: - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/utils@3.10.8(react@19.2.1)': + '@react-stately/utils@3.10.8(react@19.2.3)': dependencies: - '@swc/helpers': 0.5.17 - react: 19.2.1 + '@swc/helpers': 0.5.18 + react: 19.2.3 - '@react-stately/virtualizer@4.4.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@react-stately/virtualizer@4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@swc/helpers': 0.5.17 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-types/shared': 3.32.1(react@19.2.3) + '@swc/helpers': 0.5.18 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - '@react-types/autocomplete@3.0.0-alpha.35(react@19.2.1)': + '@react-types/autocomplete@3.0.0-alpha.35(react@19.2.3)': dependencies: - '@react-types/combobox': 3.13.9(react@19.2.1) - '@react-types/searchfield': 3.6.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/combobox': 3.13.9(react@19.2.3) + '@react-types/searchfield': 3.6.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/breadcrumbs@3.7.17(react@19.2.1)': + '@react-types/breadcrumbs@3.7.17(react@19.2.3)': dependencies: - '@react-types/link': 3.6.5(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/link': 3.6.5(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/button@3.14.1(react@19.2.1)': + '@react-types/button@3.14.1(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/calendar@3.8.0(react@19.2.1)': + '@react-types/calendar@3.8.0(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/checkbox@3.10.2(react@19.2.1)': + '@react-types/checkbox@3.10.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/color@3.1.2(react@19.2.1)': + '@react-types/color@3.1.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/slider': 3.8.2(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/slider': 3.8.2(react@19.2.3) + react: 19.2.3 - '@react-types/combobox@3.13.9(react@19.2.1)': + '@react-types/combobox@3.13.9(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/datepicker@3.13.2(react@19.2.1)': + '@react-types/datepicker@3.13.2(react@19.2.3)': dependencies: '@internationalized/date': 3.10.0 - '@react-types/calendar': 3.8.0(react@19.2.1) - '@react-types/overlays': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/calendar': 3.8.0(react@19.2.3) + '@react-types/overlays': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/dialog@3.5.22(react@19.2.1)': + '@react-types/dialog@3.5.22(react@19.2.3)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/overlays': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/form@3.7.16(react@19.2.1)': + '@react-types/form@3.7.16(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/grid@3.3.6(react@19.2.1)': + '@react-types/grid@3.3.6(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/link@3.6.5(react@19.2.1)': + '@react-types/link@3.6.5(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/listbox@3.7.4(react@19.2.1)': + '@react-types/listbox@3.7.4(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/menu@3.10.5(react@19.2.1)': + '@react-types/menu@3.10.5(react@19.2.3)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/overlays': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/meter@3.4.13(react@19.2.1)': + '@react-types/meter@3.4.13(react@19.2.3)': dependencies: - '@react-types/progress': 3.5.16(react@19.2.1) - react: 19.2.1 + '@react-types/progress': 3.5.16(react@19.2.3) + react: 19.2.3 - '@react-types/numberfield@3.8.15(react@19.2.1)': + '@react-types/numberfield@3.8.15(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/overlays@3.9.2(react@19.2.1)': + '@react-types/overlays@3.9.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/progress@3.5.16(react@19.2.1)': + '@react-types/progress@3.5.16(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/radio@3.9.2(react@19.2.1)': + '@react-types/radio@3.9.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/searchfield@3.6.6(react@19.2.1)': + '@react-types/searchfield@3.6.6(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/textfield': 3.12.6(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/textfield': 3.12.6(react@19.2.3) + react: 19.2.3 - '@react-types/select@3.11.0(react@19.2.1)': + '@react-types/select@3.11.0(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/shared@3.32.1(react@19.2.1)': + '@react-types/shared@3.32.1(react@19.2.3)': dependencies: - react: 19.2.1 + react: 19.2.3 - '@react-types/slider@3.8.2(react@19.2.1)': + '@react-types/slider@3.8.2(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/switch@3.5.15(react@19.2.1)': + '@react-types/switch@3.5.15(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/table@3.13.4(react@19.2.1)': + '@react-types/table@3.13.4(react@19.2.3)': dependencies: - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/tabs@3.3.19(react@19.2.1)': + '@react-types/tabs@3.3.19(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/textfield@3.12.6(react@19.2.1)': + '@react-types/textfield@3.12.6(react@19.2.3)': dependencies: - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - '@react-types/tooltip@3.4.21(react@19.2.1)': + '@react-types/tooltip@3.4.21(react@19.2.3)': dependencies: - '@react-types/overlays': 3.9.2(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-types/overlays': 3.9.2(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 '@redis/bloom@1.2.0(@redis/client@1.6.1)': dependencies: @@ -9953,133 +9736,142 @@ snapshots: dependencies: '@redis/client': 1.6.1 - '@rollup/plugin-alias@5.1.1(rollup@4.53.3)': + '@rollup/plugin-alias@5.1.1(rollup@4.55.1)': optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-commonjs@25.0.8(rollup@4.53.3)': + '@rollup/plugin-commonjs@25.0.8(rollup@4.55.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + '@rollup/pluginutils': 5.2.0(rollup@4.55.1) commondir: 1.0.1 estree-walker: 2.0.2 glob: 8.1.0 is-reference: 1.2.1 magic-string: 0.30.17 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-json@6.1.0(rollup@4.53.3)': + '@rollup/plugin-json@6.1.0(rollup@4.55.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + '@rollup/pluginutils': 5.2.0(rollup@4.55.1) optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.53.3)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.55.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + '@rollup/pluginutils': 5.2.0(rollup@4.55.1) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.10 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-replace@5.0.7(rollup@4.53.3)': + '@rollup/plugin-replace@5.0.7(rollup@4.55.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + '@rollup/pluginutils': 5.2.0(rollup@4.55.1) magic-string: 0.30.17 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-terser@0.4.4(rollup@4.53.3)': + '@rollup/plugin-terser@0.4.4(rollup@4.55.1)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.43.1 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/plugin-typescript@12.3.0(rollup@4.53.3)(tslib@2.8.1)(typescript@5.9.3)': + '@rollup/plugin-typescript@12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.53.3) + '@rollup/pluginutils': 5.2.0(rollup@4.55.1) resolve: 1.22.10 typescript: 5.9.3 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 tslib: 2.8.1 - '@rollup/pluginutils@5.2.0(rollup@4.53.3)': + '@rollup/pluginutils@5.2.0(rollup@4.55.1)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.53.3 + rollup: 4.55.1 - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-android-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-darwin-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-darwin-x64@4.55.1': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.55.1': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-freebsd-x64@4.55.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.55.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-musl@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-ppc64-musl@4.55.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.55.1': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.55.1': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.55.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-linux-x64-musl@4.55.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-openbsd-x64@4.55.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-openharmony-arm64@4.55.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true '@sinclair/typebox@0.27.8': {} @@ -10096,7 +9888,7 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.3)': dependencies: @@ -10203,16 +9995,16 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.17': + '@swc/helpers@0.5.18': dependencies: tslib: 2.8.1 - '@tanstack/query-core@5.90.12': {} + '@tanstack/query-core@5.90.17': {} - '@tanstack/react-query@5.90.12(react@19.2.1)': + '@tanstack/react-query@5.90.17(react@19.2.3)': dependencies: - '@tanstack/query-core': 5.90.12 - react: 19.2.1 + '@tanstack/query-core': 5.90.17 + react: 19.2.3 '@trysound/sax@0.2.0': {} @@ -10251,24 +10043,24 @@ snapshots: '@types/fs-extra@8.1.5': dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 '@types/fs-extra@9.0.13': dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 24.10.1 + '@types/node': 24.10.8 '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 - '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.7)': + '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.8)': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.8 hoist-non-react-statics: 3.3.2 '@types/istanbul-lib-coverage@2.0.6': {} @@ -10300,21 +10092,21 @@ snapshots: '@types/node@14.18.63': {} - '@types/node@24.10.1': + '@types/node@24.10.8': dependencies: undici-types: 7.16.0 '@types/normalize-package-data@2.4.4': {} - '@types/react-dom@19.2.3(@types/react@19.2.7)': + '@types/react-dom@19.2.3(@types/react@19.2.8)': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.8 '@types/react-window@1.8.8': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.8 - '@types/react@19.2.7': + '@types/react@19.2.8': dependencies: csstype: 3.2.3 @@ -10340,27 +10132,27 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 optional: true - '@umami/react-zen@0.216.0(@babel/core@7.28.3)(@types/react@19.2.7)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.1))': + '@umami/react-zen@0.216.0(@babel/core@7.28.3)(@types/react@19.2.8)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.2.0)(use-sync-external-store@1.6.0(react@19.2.3))': dependencies: '@fontsource/jetbrains-mono': 5.2.8 '@internationalized/date': 3.10.0 - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-spring/web': 9.7.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-spring/web': 9.7.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) classnames: 2.5.1 glob: 13.0.0 highlight.js: 11.11.1 - lucide-react: 0.555.0(react@19.2.1) - next: 16.0.7(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - react: 19.2.1 - react-aria-components: 1.13.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - react-dom: 19.2.1(react@19.2.1) - react-hook-form: 7.68.0(react@19.2.1) - react-icons: 5.5.0(react@19.2.1) + lucide-react: 0.555.0(react@19.2.3) + next: 16.1.1(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-aria-components: 1.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-dom: 19.2.3(react@19.2.3) + react-hook-form: 7.68.0(react@19.2.3) + react-icons: 5.5.0(react@19.2.3) thenby: 1.3.4 - zustand: 5.0.9(@types/react@19.2.7)(immer@10.2.0)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)) + zustand: 5.0.10(@types/react@19.2.8)(immer@10.2.0)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) transitivePeerDependencies: - '@babel/core' - '@opentelemetry/api' @@ -10596,12 +10388,12 @@ snapshots: dependencies: '@babel/types': 7.28.2 - babel-plugin-react-intl@7.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)): + babel-plugin-react-intl@7.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)): dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 '@babel/types': 7.28.2 - '@formatjs/ts-transformer': 2.13.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + '@formatjs/ts-transformer': 2.13.0(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)) '@types/babel__core': 7.20.5 '@types/fs-extra': 9.0.13 '@types/schema-utils': 2.4.0 @@ -10643,6 +10435,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.9.14: {} + bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 @@ -10757,15 +10551,13 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.25.2 - caniuse-lite: 1.0.30001741 + caniuse-lite: 1.0.30001764 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 caniuse-lite@1.0.30001735: {} - caniuse-lite@1.0.30001741: {} - - caniuse-lite@1.0.30001759: {} + caniuse-lite@1.0.30001764: {} caseless@0.12.0: {} @@ -10876,18 +10668,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colord@2.9.3: {} colorette@1.4.0: {} @@ -10948,13 +10728,13 @@ snapshots: optionalDependencies: typescript: 5.9.3 - create-jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + create-jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -11289,13 +11069,14 @@ snapshots: rimraf: 3.0.2 slash: 3.0.0 - del@8.0.0: + del@8.0.1: dependencies: globby: 14.1.0 is-glob: 4.0.3 is-path-cwd: 3.0.0 is-path-inside: 4.0.0 - p-map: 7.0.3 + p-map: 7.0.4 + presentable-error: 0.0.1 slash: 5.1.0 delayed-stream@1.0.0: {} @@ -11310,9 +11091,6 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@2.0.4: - optional: true - detect-libc@2.1.2: optional: true @@ -11388,7 +11166,7 @@ snapshots: effect@3.18.4: dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 electron-to-chromium@1.5.202: {} @@ -11627,10 +11405,10 @@ snapshots: extend@3.0.2: {} - extract-react-intl-messages@4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)): + extract-react-intl-messages@4.1.1(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)): dependencies: '@babel/core': 7.28.3 - babel-plugin-react-intl: 7.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)) + babel-plugin-react-intl: 7.9.4(ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3)) flat: 5.0.2 glob: 7.2.3 js-yaml: 3.14.1 @@ -11727,7 +11505,7 @@ snapshots: dependencies: magic-string: 0.30.21 mlly: 1.8.0 - rollup: 4.53.3 + rollup: 4.55.1 flat-cache@3.2.0: dependencies: @@ -11770,7 +11548,7 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.3.2: + fs-extra@11.3.3: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 @@ -12132,9 +11910,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -12358,7 +12133,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 co: 4.6.0 dedent: 1.6.0 @@ -12378,16 +12153,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + jest-cli@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + create-jest: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -12397,7 +12172,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + jest-config@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: '@babel/core': 7.28.3 '@jest/test-sequencer': 29.7.0 @@ -12422,8 +12197,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 24.10.1 - ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) + '@types/node': 24.10.8 + ts-node: 10.9.2(@types/node@24.10.8)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -12459,7 +12234,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -12469,7 +12244,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 24.10.1 + '@types/node': 24.10.8 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -12527,13 +12302,13 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-util: 29.7.0 jest-mock@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-util: 30.0.5 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -12570,7 +12345,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -12598,7 +12373,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.2 @@ -12644,7 +12419,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -12653,7 +12428,7 @@ snapshots: jest-util@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 24.10.1 + '@types/node': 24.10.8 chalk: 4.1.2 ci-info: 4.3.0 graceful-fs: 4.2.11 @@ -12672,7 +12447,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 24.10.1 + '@types/node': 24.10.8 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -12681,17 +12456,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 24.10.1 + '@types/node': 24.10.8 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + jest-cli: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -12959,13 +12734,13 @@ snapshots: lru.min@1.1.3: {} - lucide-react@0.543.0(react@19.2.1): + lucide-react@0.543.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 - lucide-react@0.555.0(react@19.2.1): + lucide-react@0.555.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 magic-string@0.30.17: dependencies: @@ -12997,7 +12772,7 @@ snapshots: mathml-tag-names@2.1.3: {} - maxmind@5.0.1: + maxmind@5.0.3: dependencies: mmdb-lib: 3.0.1 tiny-lru: 11.4.5 @@ -13154,15 +12929,15 @@ snapshots: neo-async@2.6.2: {} - next@15.5.7(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + next@15.5.9(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@next/env': 15.5.7 + '@next/env': 15.5.9 '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001741 + caniuse-lite: 1.0.30001764 postcss: 8.4.31 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.3) optionalDependencies: '@next/swc-darwin-arm64': 15.5.7 '@next/swc-darwin-x64': 15.5.7 @@ -13173,29 +12948,30 @@ snapshots: '@next/swc-win32-arm64-msvc': 15.5.7 '@next/swc-win32-x64-msvc': 15.5.7 babel-plugin-react-compiler: 19.1.0-rc.2 - sharp: 0.34.3 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - next@16.0.7(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + next@16.1.1(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@next/env': 16.0.7 + '@next/env': 16.1.1 '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001759 + baseline-browser-mapping: 2.9.14 + caniuse-lite: 1.0.30001764 postcss: 8.4.31 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.3) optionalDependencies: - '@next/swc-darwin-arm64': 16.0.7 - '@next/swc-darwin-x64': 16.0.7 - '@next/swc-linux-arm64-gnu': 16.0.7 - '@next/swc-linux-arm64-musl': 16.0.7 - '@next/swc-linux-x64-gnu': 16.0.7 - '@next/swc-linux-x64-musl': 16.0.7 - '@next/swc-win32-arm64-msvc': 16.0.7 - '@next/swc-win32-x64-msvc': 16.0.7 + '@next/swc-darwin-arm64': 16.1.1 + '@next/swc-darwin-x64': 16.1.1 + '@next/swc-linux-arm64-gnu': 16.1.1 + '@next/swc-linux-arm64-musl': 16.1.1 + '@next/swc-linux-x64-gnu': 16.1.1 + '@next/swc-linux-x64-musl': 16.1.1 + '@next/swc-win32-arm64-msvc': 16.1.1 + '@next/swc-win32-x64-msvc': 16.1.1 babel-plugin-react-compiler: 19.1.0-rc.2 sharp: 0.34.5 transitivePeerDependencies: @@ -13330,7 +13106,7 @@ snapshots: dependencies: aggregate-error: 3.1.0 - p-map@7.0.3: {} + p-map@7.0.4: {} p-queue@6.6.2: dependencies: @@ -13401,18 +13177,18 @@ snapshots: performance-now@2.1.0: {} - pg-cloudflare@1.2.7: + pg-cloudflare@1.3.0: optional: true - pg-connection-string@2.9.1: {} + pg-connection-string@2.10.0: {} pg-int8@1.0.1: {} - pg-pool@3.10.1(pg@8.16.3): + pg-pool@3.11.0(pg@8.17.0): dependencies: - pg: 8.16.3 + pg: 8.17.0 - pg-protocol@1.10.3: {} + pg-protocol@1.11.0: {} pg-types@2.2.0: dependencies: @@ -13422,15 +13198,15 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.16.3: + pg@8.17.0: dependencies: - pg-connection-string: 2.9.1 - pg-pool: 3.10.1(pg@8.16.3) - pg-protocol: 1.10.3 + pg-connection-string: 2.10.0 + pg-pool: 3.11.0(pg@8.17.0) + pg-protocol: 1.11.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: - pg-cloudflare: 1.2.7 + pg-cloudflare: 1.3.0 pgpass@1.0.5: dependencies: @@ -13608,13 +13384,13 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 - postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: postcss: 8.5.6 - ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@24.10.8)(typescript@5.9.3) postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1): dependencies: @@ -13916,6 +13692,8 @@ snapshots: postgres@3.4.7: {} + presentable-error@0.0.1: {} + prettier@2.8.8: {} pretty-bytes@5.6.0: {} @@ -13932,12 +13710,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - prisma@7.1.0(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.3): + prisma@7.2.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3): dependencies: - '@prisma/config': 7.1.0 - '@prisma/dev': 0.15.0(typescript@5.9.3) - '@prisma/engines': 7.1.0 - '@prisma/studio-core': 0.8.2(@types/react@19.2.7)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@prisma/config': 7.2.0 + '@prisma/dev': 0.17.0(typescript@5.9.3) + '@prisma/engines': 7.2.0 + '@prisma/studio-core': 0.9.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) mysql2: 3.15.3 postgres: 3.4.7 optionalDependencies: @@ -14005,115 +13783,115 @@ snapshots: defu: 6.1.4 destr: 2.0.5 - react-aria-components@1.13.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-aria-components@1.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@internationalized/date': 3.10.0 '@internationalized/string': 3.2.7 - '@react-aria/autocomplete': 3.0.0-rc.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/collections': 3.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/dnd': 3.11.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@react-aria/autocomplete': 3.0.0-rc.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/collections': 3.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/dnd': 3.11.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-aria/live-announcer': 3.4.4 - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/toolbar': 3.0.0-beta.21(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/virtualizer': 4.1.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/autocomplete': 3.0.0-beta.3(react@19.2.1) - '@react-stately/layout': 4.5.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/table': 3.15.1(react@19.2.1) - '@react-stately/utils': 3.10.8(react@19.2.1) - '@react-stately/virtualizer': 4.4.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/form': 3.7.16(react@19.2.1) - '@react-types/grid': 3.3.6(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - '@react-types/table': 3.13.4(react@19.2.1) - '@swc/helpers': 0.5.17 + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/toolbar': 3.0.0-beta.21(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/virtualizer': 4.1.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/autocomplete': 3.0.0-beta.3(react@19.2.3) + '@react-stately/layout': 4.5.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/table': 3.15.1(react@19.2.3) + '@react-stately/utils': 3.10.8(react@19.2.3) + '@react-stately/virtualizer': 4.4.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/form': 3.7.16(react@19.2.3) + '@react-types/grid': 3.3.6(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + '@react-types/table': 3.13.4(react@19.2.3) + '@swc/helpers': 0.5.18 client-only: 0.0.1 - react: 19.2.1 - react-aria: 3.44.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - react-dom: 19.2.1(react@19.2.1) - react-stately: 3.42.0(react@19.2.1) - use-sync-external-store: 1.6.0(react@19.2.1) + react: 19.2.3 + react-aria: 3.44.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-dom: 19.2.3(react@19.2.3) + react-stately: 3.42.0(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) - react-aria@3.44.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-aria@3.44.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@internationalized/string': 3.2.7 - '@react-aria/breadcrumbs': 3.5.29(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/button': 3.14.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/calendar': 3.9.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/checkbox': 3.16.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/color': 3.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/combobox': 3.14.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/datepicker': 3.15.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/dialog': 3.5.31(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/disclosure': 3.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/dnd': 3.11.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/focus': 3.21.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/gridlist': 3.14.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/i18n': 3.12.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/interactions': 3.25.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/label': 3.7.22(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/landmark': 3.0.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/link': 3.8.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/listbox': 3.15.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/menu': 3.19.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/meter': 3.4.27(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/numberfield': 3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/overlays': 3.30.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/progress': 3.4.27(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/radio': 3.12.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/searchfield': 3.8.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/select': 3.17.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/selection': 3.26.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/separator': 3.4.13(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/slider': 3.8.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/ssr': 3.9.10(react@19.2.1) - '@react-aria/switch': 3.7.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/table': 3.17.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/tabs': 3.10.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/tag': 3.7.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/textfield': 3.18.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/toast': 3.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/tooltip': 3.8.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/tree': 3.1.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/utils': 3.31.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + '@react-aria/breadcrumbs': 3.5.29(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/button': 3.14.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/calendar': 3.9.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/checkbox': 3.16.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/color': 3.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/combobox': 3.14.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/datepicker': 3.15.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/dialog': 3.5.31(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/disclosure': 3.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/dnd': 3.11.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/focus': 3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/gridlist': 3.14.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/i18n': 3.12.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/label': 3.7.22(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/landmark': 3.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/link': 3.8.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/listbox': 3.15.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/menu': 3.19.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/meter': 3.4.27(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/numberfield': 3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/overlays': 3.30.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/progress': 3.4.27(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/radio': 3.12.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/searchfield': 3.8.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/select': 3.17.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/selection': 3.26.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/separator': 3.4.13(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/slider': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/ssr': 3.9.10(react@19.2.3) + '@react-aria/switch': 3.7.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/table': 3.17.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/tabs': 3.10.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/tag': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/textfield': 3.18.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/toast': 3.0.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/tooltip': 3.8.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/tree': 3.1.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/utils': 3.31.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-aria/visually-hidden': 3.8.28(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - react-dom@19.2.1(react@19.2.1): + react-dom@19.2.3(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 scheduler: 0.27.0 - react-error-boundary@4.1.2(react@19.2.1): + react-error-boundary@4.1.2(react@19.2.3): dependencies: '@babel/runtime': 7.28.3 - react: 19.2.1 + react: 19.2.3 - react-hook-form@7.68.0(react@19.2.1): + react-hook-form@7.68.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 - react-icons@5.5.0(react@19.2.1): + react-icons@5.5.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 - react-intl@7.1.14(react@19.2.1)(typescript@5.9.3): + react-intl@7.1.14(react@19.2.3)(typescript@5.9.3): dependencies: '@formatjs/ecma402-abstract': 2.3.6 '@formatjs/icu-messageformat-parser': 2.11.4 '@formatjs/intl': 3.1.8(typescript@5.9.3) - '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.7) - '@types/react': 19.2.7 + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.8) + '@types/react': 19.2.8 hoist-non-react-statics: 3.3.2 intl-messageformat: 10.7.18 - react: 19.2.1 + react: 19.2.3 tslib: 2.8.1 optionalDependencies: typescript: 5.9.3 @@ -14122,69 +13900,69 @@ snapshots: react-is@18.3.1: {} - react-redux@9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.2.8)(react@19.2.3)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 - react: 19.2.1 - use-sync-external-store: 1.5.0(react@19.2.1) + react: 19.2.3 + use-sync-external-store: 1.5.0(react@19.2.3) optionalDependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.8 redux: 5.0.1 - react-simple-maps@2.3.0(prop-types@15.8.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-simple-maps@2.3.0(prop-types@15.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: d3-geo: 2.0.2 d3-selection: 2.0.0 d3-zoom: 2.0.0 prop-types: 15.8.1 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) topojson-client: 3.1.0 - react-stately@3.42.0(react@19.2.1): + react-stately@3.42.0(react@19.2.3): dependencies: - '@react-stately/calendar': 3.9.0(react@19.2.1) - '@react-stately/checkbox': 3.7.2(react@19.2.1) - '@react-stately/collections': 3.12.8(react@19.2.1) - '@react-stately/color': 3.9.2(react@19.2.1) - '@react-stately/combobox': 3.12.0(react@19.2.1) - '@react-stately/data': 3.14.1(react@19.2.1) - '@react-stately/datepicker': 3.15.2(react@19.2.1) - '@react-stately/disclosure': 3.0.8(react@19.2.1) - '@react-stately/dnd': 3.7.1(react@19.2.1) - '@react-stately/form': 3.2.2(react@19.2.1) - '@react-stately/list': 3.13.1(react@19.2.1) - '@react-stately/menu': 3.9.8(react@19.2.1) - '@react-stately/numberfield': 3.10.2(react@19.2.1) - '@react-stately/overlays': 3.6.20(react@19.2.1) - '@react-stately/radio': 3.11.2(react@19.2.1) - '@react-stately/searchfield': 3.5.16(react@19.2.1) - '@react-stately/select': 3.8.0(react@19.2.1) - '@react-stately/selection': 3.20.6(react@19.2.1) - '@react-stately/slider': 3.7.2(react@19.2.1) - '@react-stately/table': 3.15.1(react@19.2.1) - '@react-stately/tabs': 3.8.6(react@19.2.1) - '@react-stately/toast': 3.1.2(react@19.2.1) - '@react-stately/toggle': 3.9.2(react@19.2.1) - '@react-stately/tooltip': 3.5.8(react@19.2.1) - '@react-stately/tree': 3.9.3(react@19.2.1) - '@react-types/shared': 3.32.1(react@19.2.1) - react: 19.2.1 + '@react-stately/calendar': 3.9.0(react@19.2.3) + '@react-stately/checkbox': 3.7.2(react@19.2.3) + '@react-stately/collections': 3.12.8(react@19.2.3) + '@react-stately/color': 3.9.2(react@19.2.3) + '@react-stately/combobox': 3.12.0(react@19.2.3) + '@react-stately/data': 3.14.1(react@19.2.3) + '@react-stately/datepicker': 3.15.2(react@19.2.3) + '@react-stately/disclosure': 3.0.8(react@19.2.3) + '@react-stately/dnd': 3.7.1(react@19.2.3) + '@react-stately/form': 3.2.2(react@19.2.3) + '@react-stately/list': 3.13.1(react@19.2.3) + '@react-stately/menu': 3.9.8(react@19.2.3) + '@react-stately/numberfield': 3.10.2(react@19.2.3) + '@react-stately/overlays': 3.6.20(react@19.2.3) + '@react-stately/radio': 3.11.2(react@19.2.3) + '@react-stately/searchfield': 3.5.16(react@19.2.3) + '@react-stately/select': 3.8.0(react@19.2.3) + '@react-stately/selection': 3.20.6(react@19.2.3) + '@react-stately/slider': 3.7.2(react@19.2.3) + '@react-stately/table': 3.15.1(react@19.2.3) + '@react-stately/tabs': 3.8.6(react@19.2.3) + '@react-stately/toast': 3.1.2(react@19.2.3) + '@react-stately/toggle': 3.9.2(react@19.2.3) + '@react-stately/tooltip': 3.5.8(react@19.2.3) + '@react-stately/tree': 3.9.3(react@19.2.3) + '@react-types/shared': 3.32.1(react@19.2.3) + react: 19.2.3 - react-use-measure@2.1.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-use-measure@2.1.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 optionalDependencies: - react-dom: 19.2.1(react@19.2.1) + react-dom: 19.2.3(react@19.2.3) - react-window@1.8.11(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-window@1.8.11(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@babel/runtime': 7.28.3 memoize-one: 5.2.1 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) - react@19.2.1: {} + react@19.2.3: {} read-babelrc-up@1.1.0: dependencies: @@ -14342,28 +14120,28 @@ snapshots: globby: 10.0.1 is-plain-object: 3.0.1 - rollup-plugin-delete@3.0.1(rollup@4.53.3): + rollup-plugin-delete@3.0.2(rollup@4.55.1): dependencies: - del: 8.0.0 - rollup: 4.53.3 + del: 8.0.1 + rollup: 4.55.1 - rollup-plugin-dts@6.3.0(rollup@4.53.3)(typescript@5.9.3): + rollup-plugin-dts@6.3.0(rollup@4.55.1)(typescript@5.9.3): dependencies: magic-string: 0.30.21 - rollup: 4.53.3 + rollup: 4.55.1 typescript: 5.9.3 optionalDependencies: '@babel/code-frame': 7.27.1 - rollup-plugin-node-externals@8.1.2(rollup@4.53.3): + rollup-plugin-node-externals@8.1.2(rollup@4.55.1): dependencies: - rollup: 4.53.3 + rollup: 4.55.1 - rollup-plugin-peer-deps-external@2.2.4(rollup@4.53.3): + rollup-plugin-peer-deps-external@2.2.4(rollup@4.55.1): dependencies: - rollup: 4.53.3 + rollup: 4.55.1 - rollup-plugin-postcss@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)): + rollup-plugin-postcss@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)): dependencies: chalk: 4.1.2 concat-with-sourcemaps: 1.1.0 @@ -14372,7 +14150,7 @@ snapshots: p-queue: 6.6.2 pify: 5.0.0 postcss: 8.5.6 - postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) postcss-modules: 4.3.1(postcss@8.5.6) promise.series: 0.2.0 resolve: 1.22.10 @@ -14386,32 +14164,35 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@4.53.3: + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 run-parallel@1.2.0: @@ -14497,36 +14278,6 @@ snapshots: setimmediate@1.0.5: {} - sharp@0.34.3: - dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.3 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 - optional: true - sharp@0.34.5: dependencies: '@img/colour': 1.0.0 @@ -14605,11 +14356,6 @@ snapshots: signal-exit@4.1.0: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - sisteransi@1.0.5: {} slash@3.0.0: {} @@ -14799,10 +14545,10 @@ snapshots: style-search@0.1.0: {} - styled-jsx@5.1.6(@babel/core@7.28.3)(react@19.2.1): + styled-jsx@5.1.6(@babel/core@7.28.3)(react@19.2.3): dependencies: client-only: 0.0.1 - react: 19.2.1 + react: 19.2.3 optionalDependencies: '@babel/core': 7.28.3 @@ -15025,12 +14771,12 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) + jest: 29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -15046,14 +14792,14 @@ snapshots: esbuild: 0.25.12 jest-util: 30.0.5 - ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3): + ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.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': 24.10.1 + '@types/node': 24.10.8 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -15079,7 +14825,7 @@ snapshots: picocolors: 1.1.1 postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 - rollup: 4.53.3 + rollup: 4.55.1 source-map: 0.7.6 sucrase: 3.35.0 tinyexec: 0.3.2 @@ -15164,7 +14910,7 @@ snapshots: ua-is-frozen@0.1.2: {} - ua-parser-js@2.0.6: + ua-parser-js@2.0.8: dependencies: detect-europe-js: 0.1.2 is-standalone-pwa: 0.1.1 @@ -15202,17 +14948,17 @@ snapshots: dependencies: punycode: 2.3.1 - use-memo-one@1.1.3(react@19.2.1): + use-memo-one@1.1.3(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 - use-sync-external-store@1.5.0(react@19.2.1): + use-sync-external-store@1.5.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 - use-sync-external-store@1.6.0(react@19.2.1): + use-sync-external-store@1.6.0(react@19.2.3): dependencies: - react: 19.2.1 + react: 19.2.3 util-deprecate@1.0.2: {} @@ -15408,11 +15154,11 @@ snapshots: dependencies: grammex: 3.1.12 - zod@4.1.13: {} + zod@4.3.5: {} - zustand@5.0.9(@types/react@19.2.7)(immer@10.2.0)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)): + zustand@5.0.10(@types/react@19.2.8)(immer@10.2.0)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)): optionalDependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.8 immer: 10.2.0 - react: 19.2.1 - use-sync-external-store: 1.6.0(react@19.2.1) + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) From 889a404650be079a4299c96c0c53456f57d83732 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 14 Jan 2026 15:33:06 -0800 Subject: [PATCH 045/412] share table schema + migration --- prisma/migrations/15_add_share/migration.sql | 41 ++++++++++++++++++++ prisma/schema.prisma | 15 ++++++- src/lib/constants.ts | 7 ++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 prisma/migrations/15_add_share/migration.sql diff --git a/prisma/migrations/15_add_share/migration.sql b/prisma/migrations/15_add_share/migration.sql new file mode 100644 index 000000000..2a867bb53 --- /dev/null +++ b/prisma/migrations/15_add_share/migration.sql @@ -0,0 +1,41 @@ +-- CreateTable +CREATE TABLE "share" ( + "share_id" UUID NOT NULL, + "entity_id" UUID NOT NULL, + "share_type" INTEGER NOT NULL, + "share_code" VARCHAR(50), + "parameters" JSONB NOT NULL, + "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6), + + CONSTRAINT "share_pkey" PRIMARY KEY ("share_id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "share_share_id_key" ON "share"("share_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "share_share_code_key" ON "share"("share_code"); + +-- CreateIndex +CREATE INDEX "share_entity_id_idx" ON "share"("entity_id"); + +-- MigrateData +INSERT INTO "share" (share_id, entity_id, share_type, share_code, parameters, created_at) +SELECT gen_random_uuid(), + website_id, + 1, + share_id, + '{}'::jsonb, + now() +FROM "website" +WHERE share_id IS NOT NULL; + +-- DropIndex +DROP INDEX "website_share_id_idx"; + +-- DropIndex +DROP INDEX "website_share_id_key"; + +-- AlterTable +ALTER TABLE "website" DROP COLUMN "share_id"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aeb11648d..e0600db0b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -67,7 +67,6 @@ model Website { id String @id @unique @map("website_id") @db.Uuid name String @db.VarChar(100) domain String? @db.VarChar(500) - shareId String? @unique @map("share_id") @db.VarChar(50) resetAt DateTime? @map("reset_at") @db.Timestamptz(6) userId String? @map("user_id") @db.Uuid teamId String? @map("team_id") @db.Uuid @@ -88,7 +87,6 @@ model Website { @@index([userId]) @@index([teamId]) @@index([createdAt]) - @@index([shareId]) @@index([createdBy]) @@map("website") } @@ -316,3 +314,16 @@ model Pixel { @@index([createdAt]) @@map("pixel") } + +model Share { + id String @id() @unique() @map("share_id") @db.Uuid + entityId String @map("entity_id") @db.Uuid + shareType Int @map("share_type") @db.Integer + shareCode String? @unique @map("share_code") @db.VarChar(50) + parameters Json + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) + + @@index([entityId]) + @@map("share") +} diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 502a3df6f..bfc80a136 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -95,6 +95,13 @@ export const EVENT_TYPE = { pixelEvent: 4, } as const; +export const ENTITY_TYPE = { + website: 1, + link: 2, + pixel: 3, + board: 4, +} as const; + export const DATA_TYPE = { string: 1, number: 2, From 29f2c7b7d46621a693cef0bb5ea7ed4f1baaae2d Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 15 Jan 2026 16:25:56 -0800 Subject: [PATCH 046/412] share api, queries, permissions, migration, entity lib --- prisma/migrations/15_add_share/migration.sql | 6 +- prisma/schema.prisma | 2 +- src/app/api/share/[shareId]/route.ts | 81 +++++++++++++++++--- src/app/api/share/[slug]/route.ts | 19 +++++ src/app/api/share/route.ts | 38 +++++++++ src/lib/entity.ts | 11 +++ src/permissions/entity.ts | 65 ++++++++++++++++ src/permissions/index.ts | 1 + src/queries/prisma/index.ts | 1 + src/queries/prisma/share.ts | 46 +++++++++++ src/queries/prisma/website.ts | 9 --- 11 files changed, 256 insertions(+), 23 deletions(-) create mode 100644 src/app/api/share/[slug]/route.ts create mode 100644 src/app/api/share/route.ts create mode 100644 src/lib/entity.ts create mode 100644 src/permissions/entity.ts create mode 100644 src/queries/prisma/share.ts diff --git a/prisma/migrations/15_add_share/migration.sql b/prisma/migrations/15_add_share/migration.sql index 2a867bb53..d9f1e7cf7 100644 --- a/prisma/migrations/15_add_share/migration.sql +++ b/prisma/migrations/15_add_share/migration.sql @@ -3,7 +3,7 @@ CREATE TABLE "share" ( "share_id" UUID NOT NULL, "entity_id" UUID NOT NULL, "share_type" INTEGER NOT NULL, - "share_code" VARCHAR(50), + "slug" VARCHAR(100) NOT NULL, "parameters" JSONB NOT NULL, "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(6), @@ -15,13 +15,13 @@ CREATE TABLE "share" ( CREATE UNIQUE INDEX "share_share_id_key" ON "share"("share_id"); -- CreateIndex -CREATE UNIQUE INDEX "share_share_code_key" ON "share"("share_code"); +CREATE UNIQUE INDEX "share_slug_key" ON "share"("slug"); -- CreateIndex CREATE INDEX "share_entity_id_idx" ON "share"("entity_id"); -- MigrateData -INSERT INTO "share" (share_id, entity_id, share_type, share_code, parameters, created_at) +INSERT INTO "share" (share_id, entity_id, share_type, slug, parameters, created_at) SELECT gen_random_uuid(), website_id, 1, diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e0600db0b..01cc372f6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -319,7 +319,7 @@ model Share { id String @id() @unique() @map("share_id") @db.Uuid entityId String @map("entity_id") @db.Uuid shareType Int @map("share_type") @db.Integer - shareCode String? @unique @map("share_code") @db.VarChar(50) + slug String @unique() @db.VarChar(100) parameters Json createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6) diff --git a/src/app/api/share/[shareId]/route.ts b/src/app/api/share/[shareId]/route.ts index bef87c4fb..da7dcf562 100644 --- a/src/app/api/share/[shareId]/route.ts +++ b/src/app/api/share/[shareId]/route.ts @@ -1,19 +1,80 @@ -import { secret } from '@/lib/crypto'; -import { createToken } from '@/lib/jwt'; -import { json, notFound } from '@/lib/response'; -import { getSharedWebsite } from '@/queries/prisma'; +import z from 'zod'; +import { parseRequest } from '@/lib/request'; +import { json, notFound, ok, unauthorized } from '@/lib/response'; +import { anyObjectParam } from '@/lib/schema'; +import { canDeleteEntity, canUpdateEntity, canViewEntity } from '@/permissions'; +import { deleteShare, getShare, updateShare } from '@/queries/prisma'; + +export async function GET(request: Request, { params }: { params: Promise<{ shareId: string }> }) { + const { auth, error } = await parseRequest(request); + + if (error) { + return error(); + } -export async function GET(_request: Request, { params }: { params: Promise<{ shareId: string }> }) { const { shareId } = await params; - const website = await getSharedWebsite(shareId); + const share = await getShare(shareId); - if (!website) { + if (!(await canViewEntity(auth, share.entityId))) { + return unauthorized(); + } + + return json(share); +} + +export async function POST(request: Request, { params }: { params: Promise<{ shareId: string }> }) { + const schema = z.object({ + slug: z.string().max(100), + parameters: anyObjectParam, + }); + + const { auth, body, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { shareId } = await params; + const { slug, parameters } = body; + + const share = await getShare(shareId); + + if (!share) { return notFound(); } - const data = { websiteId: website.id }; - const token = createToken(data, secret()); + if (!(await canUpdateEntity(auth, share.entityId))) { + return unauthorized(); + } - return json({ ...data, token }); + const result = await updateShare(shareId, { + slug, + parameters, + } as any); + + return json(result); +} + +export async function DELETE( + request: Request, + { params }: { params: Promise<{ shareId: string }> }, +) { + const { auth, error } = await parseRequest(request); + + if (error) { + return error(); + } + + const { shareId } = await params; + + const share = await getShare(shareId); + + if (!(await canDeleteEntity(auth, share.entityId))) { + return unauthorized(); + } + + await deleteShare(shareId); + + return ok(); } diff --git a/src/app/api/share/[slug]/route.ts b/src/app/api/share/[slug]/route.ts new file mode 100644 index 000000000..678795e07 --- /dev/null +++ b/src/app/api/share/[slug]/route.ts @@ -0,0 +1,19 @@ +import { secret } from '@/lib/crypto'; +import { createToken } from '@/lib/jwt'; +import { json, notFound } from '@/lib/response'; +import { getShareByCode } from '@/queries/prisma'; + +export async function GET(_request: Request, { params }: { params: Promise<{ slug: string }> }) { + const { slug } = await params; + + const share = await getShareByCode(slug); + + if (!share) { + return notFound(); + } + + const data = { shareId: share.id }; + const token = createToken(data, secret()); + + return json({ ...data, token }); +} diff --git a/src/app/api/share/route.ts b/src/app/api/share/route.ts new file mode 100644 index 000000000..99f5df0ef --- /dev/null +++ b/src/app/api/share/route.ts @@ -0,0 +1,38 @@ +import z from 'zod'; +import { uuid } from '@/lib/crypto'; +import { parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { anyObjectParam } from '@/lib/schema'; +import { canUpdateEntity } from '@/permissions'; +import { createShare } from '@/queries/prisma'; + +export async function POST(request: Request) { + const schema = z.object({ + entityId: z.uuid(), + shareType: z.coerce.number().int(), + slug: z.string().max(100), + parameters: anyObjectParam, + }); + + const { auth, body, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { entityId, shareType, slug, parameters } = body; + + if (!(await canUpdateEntity(auth, entityId))) { + return unauthorized(); + } + + const share = await createShare({ + id: uuid(), + entityId, + shareType, + slug, + parameters, + }); + + return json(share); +} diff --git a/src/lib/entity.ts b/src/lib/entity.ts new file mode 100644 index 000000000..1b64e5dd4 --- /dev/null +++ b/src/lib/entity.ts @@ -0,0 +1,11 @@ +import { getLink, getPixel, getWebsite } from '@/queries/prisma'; + +export async function getEntity(entityId: string) { + const website = await getWebsite(entityId); + const link = await getLink(entityId); + const pixel = await getPixel(entityId); + + const entity = website || link || pixel; + + return entity; +} diff --git a/src/permissions/entity.ts b/src/permissions/entity.ts new file mode 100644 index 000000000..a9194d2c9 --- /dev/null +++ b/src/permissions/entity.ts @@ -0,0 +1,65 @@ +import { hasPermission } from '@/lib/auth'; +import { PERMISSIONS } from '@/lib/constants'; +import { getEntity } from '@/lib/entity'; +import type { Auth } from '@/lib/types'; +import { getTeamUser } from '@/queries/prisma'; + +export async function canViewEntity({ user }: Auth, entityId: string) { + if (user?.isAdmin) { + return true; + } + + const entity = await getEntity(entityId); + + if (entity.userId) { + return user.id === entity.userId; + } + + if (entity.teamId) { + const teamUser = await getTeamUser(entity.teamId, user.id); + + return !!teamUser; + } + + return false; +} + +export async function canUpdateEntity({ user }: Auth, entityId: string) { + if (user.isAdmin) { + return true; + } + + const entity = await getEntity(entityId); + + if (entity.userId) { + return user.id === entity.userId; + } + + if (entity.teamId) { + const teamUser = await getTeamUser(entity.teamId, user.id); + + return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteUpdate); + } + + return false; +} + +export async function canDeleteEntity({ user }: Auth, entityId: string) { + if (user.isAdmin) { + return true; + } + + const entity = await getEntity(entityId); + + if (entity.userId) { + return user.id === entity.userId; + } + + if (entity.teamId) { + const teamUser = await getTeamUser(entity.teamId, user.id); + + return teamUser && hasPermission(teamUser.role, PERMISSIONS.websiteDelete); + } + + return false; +} diff --git a/src/permissions/index.ts b/src/permissions/index.ts index a70808e69..475cdaa48 100644 --- a/src/permissions/index.ts +++ b/src/permissions/index.ts @@ -1,3 +1,4 @@ +export * from './entity'; export * from './link'; export * from './pixel'; export * from './report'; diff --git a/src/queries/prisma/index.ts b/src/queries/prisma/index.ts index b9730f511..4dedb2b5c 100644 --- a/src/queries/prisma/index.ts +++ b/src/queries/prisma/index.ts @@ -2,6 +2,7 @@ export * from './link'; export * from './pixel'; export * from './report'; export * from './segment'; +export * from './share'; export * from './team'; export * from './teamUser'; export * from './user'; diff --git a/src/queries/prisma/share.ts b/src/queries/prisma/share.ts new file mode 100644 index 000000000..e37dc95b6 --- /dev/null +++ b/src/queries/prisma/share.ts @@ -0,0 +1,46 @@ +import type { Prisma } from '@/generated/prisma/client'; +import prisma from '@/lib/prisma'; + +export async function findShare(criteria: Prisma.ShareFindUniqueArgs) { + return prisma.client.share.findUnique(criteria); +} + +export async function getShare(entityId: string) { + return findShare({ + where: { + id: entityId, + }, + }); +} + +export async function getShareByCode(slug: string) { + return findShare({ + where: { + slug, + }, + }); +} + +export async function createShare( + data: Prisma.ShareCreateInput | Prisma.ShareUncheckedCreateInput, +) { + return prisma.client.share.create({ + data, + }); +} + +export async function updateShare( + shareId: string, + data: Prisma.ShareUpdateInput | Prisma.ShareUncheckedUpdateInput, +) { + return prisma.client.share.update({ + where: { + id: shareId, + }, + data, + }); +} + +export async function deleteShare(shareId: string) { + return prisma.client.share.delete({ where: { id: shareId } }); +} diff --git a/src/queries/prisma/website.ts b/src/queries/prisma/website.ts index 6c8625d06..fe57589c5 100644 --- a/src/queries/prisma/website.ts +++ b/src/queries/prisma/website.ts @@ -16,15 +16,6 @@ export async function getWebsite(websiteId: string) { }); } -export async function getSharedWebsite(shareId: string) { - return findWebsite({ - where: { - shareId, - deletedAt: null, - }, - }); -} - export async function getWebsites(criteria: Prisma.WebsiteFindManyArgs, filters: QueryFilters) { const { search } = filters; const { getSearchParameters, pagedQuery } = prisma; From 520c91c62142476ace9ce5ae9954487a57615400 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 16 Jan 2026 16:29:08 -0800 Subject: [PATCH 047/412] fix share api routes --- src/app/api/share/{ => id}/[shareId]/route.ts | 0 src/components/hooks/queries/useShareTokenQuery.ts | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/app/api/share/{ => id}/[shareId]/route.ts (100%) diff --git a/src/app/api/share/[shareId]/route.ts b/src/app/api/share/id/[shareId]/route.ts similarity index 100% rename from src/app/api/share/[shareId]/route.ts rename to src/app/api/share/id/[shareId]/route.ts diff --git a/src/components/hooks/queries/useShareTokenQuery.ts b/src/components/hooks/queries/useShareTokenQuery.ts index dbad3dcd7..446e33dab 100644 --- a/src/components/hooks/queries/useShareTokenQuery.ts +++ b/src/components/hooks/queries/useShareTokenQuery.ts @@ -3,7 +3,7 @@ import { useApi } from '../useApi'; const selector = (state: { shareToken: string }) => state.shareToken; -export function useShareTokenQuery(shareId: string): { +export function useShareTokenQuery(slug: string): { shareToken: any; isLoading?: boolean; error?: Error; @@ -11,9 +11,9 @@ export function useShareTokenQuery(shareId: string): { const shareToken = useApp(selector); const { get, useQuery } = useApi(); const { isLoading, error } = useQuery({ - queryKey: ['share', shareId], + queryKey: ['share', slug], queryFn: async () => { - const data = await get(`/share/${shareId}`); + const data = await get(`/share/${slug}`); setShareToken(data); From e08907d9986549e6886eab346d49498810be48e2 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 16 Jan 2026 19:52:16 -0800 Subject: [PATCH 048/412] Board setup. --- .gitignore | 3 + CLAUDE.md | 92 +++++++++++++++++++ .../{15_boards => 16_boards}/migration.sql | 0 prisma/schema.prisma | 1 - src/app/(main)/boards/BoardProvider.tsx | 4 - .../(main)/boards/[boardId]/BoardHeader.tsx | 54 ++++++++--- src/app/(main)/boards/[boardId]/BoardPage.tsx | 2 + src/app/(main)/boards/[boardId]/page.tsx | 2 +- src/app/api/boards/[boardId]/route.ts | 6 +- 9 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 CLAUDE.md rename prisma/migrations/{15_boards => 16_boards}/migration.sql (100%) diff --git a/.gitignore b/.gitignore index de893d0f1..377e4be6b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ pm2.yml *.log .vscode .tool-versions +.claude +tmpclaude* +nul # debug npm-debug.log* diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..883ee7f4d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,92 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Umami is a privacy-focused web analytics platform built with Next.js 15, React 19, and TypeScript. It serves as an alternative to Google Analytics, storing data in PostgreSQL (primary) with optional ClickHouse for time-series analytics. + +## Common Commands + +```bash +# Development +npm run dev # Start dev server on port 3001 with Turbopack +npm run build # Full production build (includes db setup, tracker, geo data) +npm run start # Start production server + +# Database +npm run build-db # Generate Prisma client +npm run update-db # Run Prisma migrations +npm run check-db # Verify database connection +npm run seed-data # Seed test data + +# Code Quality +npm run lint # Lint with Biome +npm run format # Format with Biome +npm run check # Format and lint with Biome +npm run test # Run Jest tests + +# Building specific parts +npm run build-tracker # Build client-side tracking script (Rollup) +npm run build-geo # Build geolocation database +``` + +## Architecture + +### Directory Structure +- `src/app/` - Next.js App Router (routes and API endpoints) + - `(main)/` - Authenticated app routes (dashboard, websites, teams, boards, etc.) + - `(collect)/` - Data collection routes + - `api/` - REST API endpoints +- `src/components/` - React components (charts, forms, common UI, hooks) +- `src/lib/` - Core utilities (auth, crypto, date, prisma helpers, redis) +- `src/queries/` - Data access layer (Prisma queries and raw SQL) +- `src/store/` - Zustand state stores (app, dashboard, websites, cache) +- `src/tracker/` - Client-side tracking script (lightweight IIFE) +- `prisma/` - Database schema and migrations + +### Key Patterns + +**API Request Handling** - All API endpoints use Zod validation with `parseRequest`: +```typescript +const schema = z.object({ /* fields */ }); +const { body, error } = await parseRequest(request, schema); +if (error) return error(); +``` + +**Authentication** - JWT tokens via Bearer header, share tokens via `x-umami-share-token` header for public dashboards. Role-based access: admin, manager, user. + +**Data Fetching** - React Query with 60s stale time, no retry, no refetch on window focus. + +**State Management** - Zustand for client state, localStorage for user preferences. + +**Styling** - CSS Modules with CSS variables for theming (light/dark mode). + +### Database + +- **ORM**: Prisma 7.x with PostgreSQL adapter +- **Schema**: `prisma/schema.prisma` - 14 models (User, Team, Website, Session, WebsiteEvent, EventData, etc.) +- **Query helpers**: `src/lib/prisma.ts` has dynamic SQL generation functions (`getDateSQL`, `mapFilter`, `getSearchSQL`) +- **Raw SQL**: Complex analytics queries use `{{param}}` template placeholders for safe binding + +### Tracker Script + +The tracking script in `src/tracker/index.js` is a standalone IIFE (~3-4KB) built with Rollup. It sends events to `/api/send`. Alternative script names can be configured via `TRACKER_SCRIPT_NAME` env var. + +## Environment Variables + +Key variables in `.env`: +``` +DATABASE_URL # PostgreSQL connection string (required) +APP_SECRET # Encryption/signing secret +CLICKHOUSE_URL # Optional ClickHouse for analytics +REDIS_URL # Optional Redis for caching/sessions +BASE_PATH # App base path (e.g., /analytics) +DEBUG # Debug namespaces (e.g., umami:*) +``` + +## Requirements + +- Node.js 18.18+ +- PostgreSQL 12.14+ +- pnpm (package manager) diff --git a/prisma/migrations/15_boards/migration.sql b/prisma/migrations/16_boards/migration.sql similarity index 100% rename from prisma/migrations/15_boards/migration.sql rename to prisma/migrations/16_boards/migration.sql diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 435a406f2..6e456a675 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -6,7 +6,6 @@ generator client { datasource db { provider = "postgresql" - url = env("DATABASE_URL") relationMode = "prisma" } diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx index 361366141..93d4e6f04 100644 --- a/src/app/(main)/boards/BoardProvider.tsx +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -13,9 +13,5 @@ export function BoardProvider({ boardId, children }: { boardId: string; children return ; } - if (!board) { - return null; - } - return {children}; } diff --git a/src/app/(main)/boards/[boardId]/BoardHeader.tsx b/src/app/(main)/boards/[boardId]/BoardHeader.tsx index 86bd822c2..a86ddf581 100644 --- a/src/app/(main)/boards/[boardId]/BoardHeader.tsx +++ b/src/app/(main)/boards/[boardId]/BoardHeader.tsx @@ -1,21 +1,48 @@ -import { Button, Column, Grid, Heading, Row, TextField } from '@umami/react-zen'; -import { useMessages } from '@/components/hooks'; +import { Column, Grid, Heading, LoadingButton, Row, TextField, useToast } from '@umami/react-zen'; +import { useState } from 'react'; +import { useApi, useBoard, useMessages, useModified, useNavigation } from '@/components/hooks'; export function BoardHeader() { - const { formatMessage, labels } = useMessages(); + const board = useBoard(); + const { formatMessage, labels, messages } = useMessages(); + const { post, useMutation } = useApi(); + const { touch } = useModified(); + const { router, renderUrl } = useNavigation(); + const { toast } = useToast(); const defaultName = formatMessage(labels.untitled); - const name = ''; - const description = ''; - const handleNameChange = (name: string) => { - //updateReport({ name: name || defaultName }); + const [name, setName] = useState(board?.name ?? ''); + const [description, setDescription] = useState(board?.description ?? ''); + + const { mutateAsync, isPending } = useMutation({ + mutationFn: (data: { name: string; description: string }) => { + if (board) { + return post(`/boards/${board.id}`, data); + } + return post('/boards', { ...data, type: 'dashboard', slug: '' }); + }, + }); + + const handleNameChange = (value: string) => { + setName(value); }; - const handleDescriptionChange = (description: string) => { - //updateReport({ description }); + const handleDescriptionChange = (value: string) => { + setDescription(value); }; - return

asdgfviybiyu8oaero8g9873qrgb875qh0g8

; + const handleSave = async () => { + const result = await mutateAsync({ name: name || defaultName, description }); + + toast(formatMessage(messages.saved)); + touch('boards'); + + if (board) { + touch(`board:${board.id}`); + } else if (result?.id) { + router.push(renderUrl(`/boards/${result.id}`)); + } + }; return ( - asdfasdfds - + + {formatMessage(labels.save)} + ); diff --git a/src/app/(main)/boards/[boardId]/BoardPage.tsx b/src/app/(main)/boards/[boardId]/BoardPage.tsx index 858866c16..20bdd72ca 100644 --- a/src/app/(main)/boards/[boardId]/BoardPage.tsx +++ b/src/app/(main)/boards/[boardId]/BoardPage.tsx @@ -1,5 +1,6 @@ 'use client'; import { Column } from '@umami/react-zen'; +import { BoardBody } from '@/app/(main)/boards/[boardId]/BoardBody'; import { BoardHeader } from '@/app/(main)/boards/[boardId]/BoardHeader'; import { BoardProvider } from '@/app/(main)/boards/BoardProvider'; import { PageBody } from '@/components/common/PageBody'; @@ -10,6 +11,7 @@ export function BoardPage({ boardId }: { boardId: string }) { + diff --git a/src/app/(main)/boards/[boardId]/page.tsx b/src/app/(main)/boards/[boardId]/page.tsx index 82300eb63..0eebdb2f1 100644 --- a/src/app/(main)/boards/[boardId]/page.tsx +++ b/src/app/(main)/boards/[boardId]/page.tsx @@ -4,7 +4,7 @@ import { BoardPage } from './BoardPage'; export default async function ({ params }: { params: Promise<{ boardId: string }> }) { const { boardId } = await params; - return ; + return ; } export const metadata: Metadata = { diff --git a/src/app/api/boards/[boardId]/route.ts b/src/app/api/boards/[boardId]/route.ts index a5dfd2aa3..2f94e5279 100644 --- a/src/app/api/boards/[boardId]/route.ts +++ b/src/app/api/boards/[boardId]/route.ts @@ -26,7 +26,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ boar export async function POST(request: Request, { params }: { params: Promise<{ boardId: string }> }) { const schema = z.object({ name: z.string().optional(), - domain: z.string().optional(), + description: z.string().optional(), shareId: z.string().regex(SHARE_ID_REGEX).nullable().optional(), }); @@ -37,14 +37,14 @@ export async function POST(request: Request, { params }: { params: Promise<{ boa } const { boardId } = await params; - const { name, domain, shareId } = body; + const { name, description, shareId } = body; if (!(await canUpdateBoard(auth, boardId))) { return unauthorized(); } try { - const board = await updateBoard(boardId, { name, domain, shareId }); + const board = await updateBoard(boardId, { name, description, shareId }); return Response.json(board); } catch (e: any) { From 68c56060b38fb545484b6199665a377eaed36582 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 16 Jan 2026 21:05:43 -0800 Subject: [PATCH 049/412] Add board state management with updateBoard and saveBoard methods. BoardProvider now manages local board state and exposes updateBoard for editing and saveBoard for persisting to the database. Supports both create and edit modes with proper redirect after creation. Co-Authored-By: Claude Opus 4.5 --- package.json | 1 + pnpm-lock.yaml | 14 ++++ src/app/(main)/boards/BoardProvider.tsx | 83 +++++++++++++++++-- src/app/(main)/boards/[boardId]/BoardBody.tsx | 68 ++++++++++++++- .../(main)/boards/[boardId]/BoardHeader.tsx | 50 +++-------- src/components/hooks/context/useBoard.ts | 4 +- src/lib/types.ts | 4 + 7 files changed, 176 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index e9d91cb2e..dea505fee 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "react-dom": "^19.2.3", "react-error-boundary": "^4.0.4", "react-intl": "^7.1.14", + "react-resizable-panels": "^4.4.1", "react-simple-maps": "^2.3.0", "react-use-measure": "^2.0.4", "react-window": "^1.8.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8fe45f8a..f62924439 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,6 +164,9 @@ importers: react-intl: specifier: ^7.1.14 version: 7.1.14(react@19.2.3)(typescript@5.9.3) + react-resizable-panels: + specifier: ^4.4.1 + version: 4.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-simple-maps: specifier: ^2.3.0 version: 2.3.0(prop-types@15.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6181,6 +6184,12 @@ packages: redux: optional: true + react-resizable-panels@4.4.1: + resolution: {integrity: sha512-dpM9oI6rGlAq7VYDeafSRA1JmkJv8aNuKySR+tZLQQLfaeqTnQLSM52EcoI/QdowzsjVUCk6jViKS0xHWITVRQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + react-simple-maps@2.3.0: resolution: {integrity: sha512-IZVeiPSRZKwD6I/2NvXpQ2uENYGDGZp8DvZjkapcxuJ/LQHTfl+Byb+KNgY7s+iatRA2ad8LnZ3AgqcjziCCsw==} peerDependencies: @@ -13909,6 +13918,11 @@ snapshots: '@types/react': 19.2.8 redux: 5.0.1 + react-resizable-panels@4.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-simple-maps@2.3.0(prop-types@15.8.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: d3-geo: 2.0.2 diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx index 93d4e6f04..fa9c7c901 100644 --- a/src/app/(main)/boards/BoardProvider.tsx +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -1,17 +1,86 @@ 'use client'; -import { Loading } from '@umami/react-zen'; -import { createContext, type ReactNode } from 'react'; +import { Loading, useToast } from '@umami/react-zen'; +import { createContext, type ReactNode, useCallback, useEffect, useState } from 'react'; +import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks'; import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery'; import type { Board } from '@/generated/prisma/client'; -export const BoardContext = createContext(null); +export interface BoardContextValue { + board: Partial; + updateBoard: (data: Partial) => void; + saveBoard: () => Promise; + isPending: boolean; +} -export function BoardProvider({ boardId, children }: { boardId: string; children: ReactNode }) { - const { data: board, isFetching, isLoading } = useBoardQuery(boardId); +export const BoardContext = createContext(null); - if (isFetching && isLoading) { +const defaultBoard: Partial = { + name: '', + description: '', +}; + +export function BoardProvider({ boardId, children }: { boardId?: string; children: ReactNode }) { + const { data, isFetching, isLoading } = useBoardQuery(boardId); + const { post, useMutation } = useApi(); + const { touch } = useModified(); + const { toast } = useToast(); + const { formatMessage, labels, messages } = useMessages(); + const { router, renderUrl } = useNavigation(); + + const [board, setBoard] = useState>(data ?? defaultBoard); + + useEffect(() => { + if (data) { + setBoard(data); + } + }, [data]); + + const { mutateAsync, isPending } = useMutation({ + mutationFn: (boardData: Partial) => { + if (boardData.id) { + return post(`/boards/${boardData.id}`, boardData); + } + return post('/boards', { ...boardData, type: 'dashboard', slug: '' }); + }, + }); + + const updateBoard = useCallback((data: Partial) => { + setBoard(current => ({ ...current, ...data })); + }, []); + + const saveBoard = useCallback(async () => { + const defaultName = formatMessage(labels.untitled); + const result = await mutateAsync({ ...board, name: board.name || defaultName }); + + toast(formatMessage(messages.saved)); + touch('boards'); + + if (board.id) { + touch(`board:${board.id}`); + } else if (result?.id) { + router.push(renderUrl(`/boards/${result.id}`)); + } + + return result; + }, [ + board, + mutateAsync, + toast, + formatMessage, + labels.untitled, + messages.saved, + touch, + router, + renderUrl, + ]); + + if (boardId && isFetching && isLoading) { return ; } - return {children}; + return ( + + {children} + + ); } diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx index 1728a08db..647158728 100644 --- a/src/app/(main)/boards/[boardId]/BoardBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx @@ -1,3 +1,69 @@ +import { Button, Column, Icon, Row } from '@umami/react-zen'; +import { produce } from 'immer'; +import { v4 as uuid } from 'uuid'; +import { useBoard } from '@/components/hooks'; +import { Plus } from '@/components/icons'; + export function BoardBody() { - return

i am bored.

; + const { board, updateBoard, saveBoard, isPending } = useBoard(); + + console.log({ board }); + + const handleAddRow = () => { + updateBoard({ + parameters: produce(board.parameters, draft => { + if (!draft.rows) { + draft.rows = []; + } + draft.rows.push({ id: uuid(), components: [] }); + }), + }); + }; + + return ( + + {board?.parameters?.rows?.map((row, rowIndex) => { + return ; + })} + + + + + ); +} + +function BoardComponent() { + return hi; +} + +function BoardRow({ rowIndex, components }: { rowIndex: number; components: any[] }) { + const { board, updateBoard } = useBoard(); + + const handleAddComponent = () => { + updateBoard({ + parameters: produce(board.parameters, draft => { + if (!draft.rows[rowIndex]) { + draft.rows[rowIndex] = { id: uuid(), components: [] }; + } + draft.rows[rowIndex].components.push({ id: uuid(), type: 'text', value: '' }); + }), + }); + }; + + return ( + + {components?.map(component => { + return ; + })} + + + ); } diff --git a/src/app/(main)/boards/[boardId]/BoardHeader.tsx b/src/app/(main)/boards/[boardId]/BoardHeader.tsx index a86ddf581..18492e04a 100644 --- a/src/app/(main)/boards/[boardId]/BoardHeader.tsx +++ b/src/app/(main)/boards/[boardId]/BoardHeader.tsx @@ -1,47 +1,21 @@ -import { Column, Grid, Heading, LoadingButton, Row, TextField, useToast } from '@umami/react-zen'; -import { useState } from 'react'; -import { useApi, useBoard, useMessages, useModified, useNavigation } from '@/components/hooks'; +import { Column, Grid, Heading, LoadingButton, Row, TextField } from '@umami/react-zen'; +import { useBoard, useMessages } from '@/components/hooks'; export function BoardHeader() { - const board = useBoard(); - const { formatMessage, labels, messages } = useMessages(); - const { post, useMutation } = useApi(); - const { touch } = useModified(); - const { router, renderUrl } = useNavigation(); - const { toast } = useToast(); + const { board, updateBoard, saveBoard, isPending } = useBoard(); + const { formatMessage, labels } = useMessages(); const defaultName = formatMessage(labels.untitled); - const [name, setName] = useState(board?.name ?? ''); - const [description, setDescription] = useState(board?.description ?? ''); - - const { mutateAsync, isPending } = useMutation({ - mutationFn: (data: { name: string; description: string }) => { - if (board) { - return post(`/boards/${board.id}`, data); - } - return post('/boards', { ...data, type: 'dashboard', slug: '' }); - }, - }); - const handleNameChange = (value: string) => { - setName(value); + updateBoard({ name: value }); }; const handleDescriptionChange = (value: string) => { - setDescription(value); + updateBoard({ description: value }); }; - const handleSave = async () => { - const result = await mutateAsync({ name: name || defaultName, description }); - - toast(formatMessage(messages.saved)); - touch('boards'); - - if (board) { - touch(`board:${board.id}`); - } else if (result?.id) { - router.push(renderUrl(`/boards/${result.id}`)); - } + const handleSave = () => { + saveBoard(); }; return ( @@ -57,26 +31,26 @@ export function BoardHeader() { - {name} + {board?.name} - {description} + {board?.description}
diff --git a/src/components/hooks/context/useBoard.ts b/src/components/hooks/context/useBoard.ts index 0281dd8d3..cb8b28d8a 100644 --- a/src/components/hooks/context/useBoard.ts +++ b/src/components/hooks/context/useBoard.ts @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { BoardContext } from '@/app/(main)/boards/BoardProvider'; +import { BoardContext, type BoardContextValue } from '@/app/(main)/boards/BoardProvider'; -export function useBoard() { +export function useBoard(): BoardContextValue { return useContext(BoardContext); } diff --git a/src/lib/types.ts b/src/lib/types.ts index 9c0619794..458f899dc 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -141,3 +141,7 @@ export interface ApiError extends Error { code?: string; message: string; } + +export interface BoardData { + rows: { id: string; name: string; value: number }[]; +} From d9f698ca42a325446b9f3fd3fec93755d981182a Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 18 Jan 2026 04:20:36 -0800 Subject: [PATCH 050/412] Board editing. --- CLAUDE.md | 4 + package.json | 2 +- pnpm-lock.yaml | 78 ++++------ scripts/check-db.js | 2 +- src/app/(main)/boards/BoardProvider.tsx | 3 +- src/app/(main)/boards/[boardId]/BoardBody.tsx | 147 ++++++++++++++---- src/app/api/boards/[boardId]/route.ts | 7 +- src/lib/types.ts | 26 +++- 8 files changed, 183 insertions(+), 86 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 883ee7f4d..a7ad68f90 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,3 +90,7 @@ DEBUG # Debug namespaces (e.g., umami:*) - Node.js 18.18+ - PostgreSQL 12.14+ - pnpm (package manager) + +## Git Workflow + +Always ask for confirmation before running `git commit` or `git push`. diff --git a/package.json b/package.json index dea505fee..326f17206 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "stylelint-config-css-modules": "^4.5.1", "stylelint-config-prettier": "^9.0.3", "stylelint-config-recommended": "^14.0.0", - "tar": "^6.1.2", + "tar": "^7.5.3", "ts-jest": "^29.4.6", "ts-node": "^10.9.1", "tsup": "^8.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f62924439..daefaf065 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -316,8 +316,8 @@ importers: specifier: ^14.0.0 version: 14.0.1(stylelint@15.11.0(typescript@5.9.3)) tar: - specifier: ^6.1.2 - version: 6.2.1 + specifier: ^7.5.3 + version: 7.5.3 ts-jest: specifier: ^29.4.6 version: 29.4.6(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.12)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.10.8)(ts-node@10.9.2(@types/node@24.10.8)(typescript@5.9.3)))(typescript@5.9.3) @@ -1479,6 +1479,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -3279,9 +3283,9 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} @@ -4066,10 +4070,6 @@ packages: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -5180,21 +5180,13 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} @@ -6781,9 +6773,9 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} + tar@7.5.3: + resolution: {integrity: sha512-ENg5JUHUm2rDD7IvKNFGzyElLXNjachNLp6RaGf4+JOgxXHkqA+gq81ZAMCUmtMtqBsoU62lcp6S27g1LCYGGQ==} + engines: {node: '>=18'} terser@5.43.1: resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} @@ -7190,6 +7182,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -8224,6 +8220,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -10609,7 +10609,7 @@ snapshots: dependencies: readdirp: 4.1.2 - chownr@2.0.0: {} + chownr@3.0.0: {} ci-info@3.9.0: {} @@ -11576,10 +11576,6 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -12882,18 +12878,11 @@ snapshots: minimist@1.2.8: {} - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: + minizlib@3.1.0: dependencies: - minipass: 3.3.6 - yallist: 4.0.0 + minipass: 7.1.2 mkdirp@1.0.4: {} @@ -14706,14 +14695,13 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tar@6.2.1: + tar@7.5.3: dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 terser@5.43.1: dependencies: @@ -15132,6 +15120,8 @@ snapshots: yallist@4.0.0: {} + yallist@5.0.0: {} + yaml@1.10.2: {} yaml@2.8.1: {} diff --git a/scripts/check-db.js b/scripts/check-db.js index 68374f6f5..8c806cd8f 100644 --- a/scripts/check-db.js +++ b/scripts/check-db.js @@ -48,7 +48,7 @@ async function checkConnection() { success('Database connection successful.'); } catch (e) { - throw new Error('Unable to connect to the database: ' + e.message); + throw new Error(`Unable to connect to the database: ${e.message}`); } } diff --git a/src/app/(main)/boards/BoardProvider.tsx b/src/app/(main)/boards/BoardProvider.tsx index fa9c7c901..783f92eff 100644 --- a/src/app/(main)/boards/BoardProvider.tsx +++ b/src/app/(main)/boards/BoardProvider.tsx @@ -3,7 +3,7 @@ import { Loading, useToast } from '@umami/react-zen'; import { createContext, type ReactNode, useCallback, useEffect, useState } from 'react'; import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks'; import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery'; -import type { Board } from '@/generated/prisma/client'; +import type { Board } from '@/lib/types'; export interface BoardContextValue { board: Partial; @@ -17,6 +17,7 @@ export const BoardContext = createContext(null); const defaultBoard: Partial = { name: '', description: '', + parameters: { rows: [] }, }; export function BoardProvider({ boardId, children }: { boardId?: string; children: ReactNode }) { diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx index 647158728..0c05486f9 100644 --- a/src/app/(main)/boards/[boardId]/BoardBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx @@ -1,8 +1,18 @@ -import { Button, Column, Icon, Row } from '@umami/react-zen'; +import { Box, Button, Column, Icon, Row, Tooltip, TooltipTrigger } from '@umami/react-zen'; import { produce } from 'immer'; +import { Fragment, type ReactElement } from 'react'; +import { Group, Panel, Separator } from 'react-resizable-panels'; import { v4 as uuid } from 'uuid'; import { useBoard } from '@/components/hooks'; -import { Plus } from '@/components/icons'; +import { Minus, Plus } from '@/components/icons'; +import type { BoardColumn as BoardColumnType } from '@/lib/types'; + +const CATALOG = { + text: { + label: 'Text', + component: BoardColumn, + }, +}; export function BoardBody() { const { board, updateBoard, saveBoard, isPending } = useBoard(); @@ -15,55 +25,126 @@ export function BoardBody() { if (!draft.rows) { draft.rows = []; } - draft.rows.push({ id: uuid(), components: [] }); + draft.rows.push({ id: uuid(), columns: [{ id: uuid(), component: null }] }); + }), + }); + }; + + const handleRemoveRow = (id: string) => { + console.log('Removing row', id); + updateBoard({ + parameters: produce(board.parameters, draft => { + if (!draft.rows) { + return; + } + + draft.rows = draft.rows.filter(row => row?.id !== id); + }), + }); + }; + + const rows = board?.parameters?.rows ?? []; + const minHeight = 300 * (rows.length || 1); + + return ( + <> + + {rows.map((row, index) => ( + + + + + {index < rows.length - 1 && } + + ))} + + + + + Add row + + + + ); +} + +function BoardRow({ + rowId, + columns, + onRemove, +}: { + rowId: string; + columns: BoardColumnType[]; + onAddComponent?: () => void; + onRemove?: (id: string) => void; +}) { + const { board, updateBoard } = useBoard(); + + const handleAddColumn = () => { + updateBoard({ + parameters: produce(board.parameters, draft => { + const rowIndex = draft.rows.findIndex(row => row.id === rowId); + const row = draft.rows[rowIndex]; + + if (!row) { + draft.rows[rowIndex] = { id: uuid(), columns: [] }; + } + row.columns.push({ id: uuid(), component: null }); }), }); }; return ( - - {board?.parameters?.rows?.map((row, rowIndex) => { - return ; - })} - - - - + + + Remove row + + + ); } -function BoardComponent() { - return hi; -} - -function BoardRow({ rowIndex, components }: { rowIndex: number; components: any[] }) { - const { board, updateBoard } = useBoard(); - - const handleAddComponent = () => { - updateBoard({ - parameters: produce(board.parameters, draft => { - if (!draft.rows[rowIndex]) { - draft.rows[rowIndex] = { id: uuid(), components: [] }; - } - draft.rows[rowIndex].components.push({ id: uuid(), type: 'text', value: '' }); - }), - }); - }; +function BoardColumn({ id, component }: { id: string; component?: ReactElement }) { + const handleAddComponent = () => {}; return ( - - {components?.map(component => { - return ; - })} + - + ); } diff --git a/src/app/api/boards/[boardId]/route.ts b/src/app/api/boards/[boardId]/route.ts index 2f94e5279..24bae4dcd 100644 --- a/src/app/api/boards/[boardId]/route.ts +++ b/src/app/api/boards/[boardId]/route.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import { SHARE_ID_REGEX } from '@/lib/constants'; import { parseRequest } from '@/lib/request'; import { badRequest, json, ok, serverError, unauthorized } from '@/lib/response'; import { canDeleteBoard, canUpdateBoard, canViewBoard } from '@/permissions'; @@ -27,7 +26,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ boa const schema = z.object({ name: z.string().optional(), description: z.string().optional(), - shareId: z.string().regex(SHARE_ID_REGEX).nullable().optional(), + parameters: z.object({}).passthrough().optional(), }); const { auth, body, error } = await parseRequest(request, schema); @@ -37,14 +36,14 @@ export async function POST(request: Request, { params }: { params: Promise<{ boa } const { boardId } = await params; - const { name, description, shareId } = body; + const { name, description, parameters } = body; if (!(await canUpdateBoard(auth, boardId))) { return unauthorized(); } try { - const board = await updateBoard(boardId, { name, description, shareId }); + const board = await updateBoard(boardId, { name, description, parameters }); return Response.json(board); } catch (e: any) { diff --git a/src/lib/types.ts b/src/lib/types.ts index 458f899dc..2da6fe35a 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,4 +1,6 @@ import type { UseQueryOptions } from '@tanstack/react-query'; +import type { ReactElement } from 'react'; +import type { Board as PrismaBoard } from '@/generated/prisma/client'; import type { DATA_TYPE, OPERATORS, ROLES } from './constants'; import type { TIME_UNIT } from './date'; @@ -142,6 +144,26 @@ export interface ApiError extends Error { message: string; } -export interface BoardData { - rows: { id: string; name: string; value: number }[]; +export interface BoardComponent { + id: string; + type: string; + value: string; +} + +export interface BoardColumn { + id: string; + component?: ReactElement; +} + +export interface BoardRow { + id: string; + columns: BoardColumn[]; +} + +export interface BoardParameters { + rows?: BoardRow[]; +} + +export interface Board extends Omit { + parameters: BoardParameters; } From ff6575ff5450369d881a984a13d1e1156141b618 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 18 Jan 2026 20:17:21 -0800 Subject: [PATCH 051/412] Add move row up/down functionality to board editor. Rows can now be reordered using up/down buttons. Buttons are disabled at boundaries (up disabled on first row, down disabled on last row). Co-Authored-By: Claude Opus 4.5 --- src/app/(main)/boards/[boardId]/BoardBody.tsx | 148 +++++++++++++----- 1 file changed, 113 insertions(+), 35 deletions(-) diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx index 0c05486f9..e1bc77ad0 100644 --- a/src/app/(main)/boards/[boardId]/BoardBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx @@ -4,7 +4,7 @@ import { Fragment, type ReactElement } from 'react'; import { Group, Panel, Separator } from 'react-resizable-panels'; import { v4 as uuid } from 'uuid'; import { useBoard } from '@/components/hooks'; -import { Minus, Plus } from '@/components/icons'; +import { ChevronDown, Minus, Plus } from '@/components/icons'; import type { BoardColumn as BoardColumnType } from '@/lib/types'; const CATALOG = { @@ -14,6 +14,12 @@ const CATALOG = { }, }; +const MIN_HEIGHT = 300; +const MAX_HEIGHT = 600; +const MIN_WIDTH = 300; +const MARGIN = 10; +const MAX_COLUMNS = 4; + export function BoardBody() { const { board, updateBoard, saveBoard, isPending } = useBoard(); @@ -31,7 +37,6 @@ export function BoardBody() { }; const handleRemoveRow = (id: string) => { - console.log('Removing row', id); updateBoard({ parameters: produce(board.parameters, draft => { if (!draft.rows) { @@ -43,44 +48,90 @@ export function BoardBody() { }); }; + const handleMoveRowUp = (id: string) => { + updateBoard({ + parameters: produce(board.parameters, draft => { + if (!draft.rows) return; + + const index = draft.rows.findIndex(row => row.id === id); + if (index > 0) { + const temp = draft.rows[index - 1]; + draft.rows[index - 1] = draft.rows[index]; + draft.rows[index] = temp; + } + }), + }); + }; + + const handleMoveRowDown = (id: string) => { + updateBoard({ + parameters: produce(board.parameters, draft => { + if (!draft.rows) return; + + const index = draft.rows.findIndex(row => row.id === id); + if (index < draft.rows.length - 1) { + const temp = draft.rows[index + 1]; + draft.rows[index + 1] = draft.rows[index]; + draft.rows[index] = temp; + } + }), + }); + }; + const rows = board?.parameters?.rows ?? []; - const minHeight = 300 * (rows.length || 1); + const rowCount = (rows.length || 1) + 1; + const minHeight = (MAX_HEIGHT + MARGIN) * rowCount; return ( - <> - - {rows.map((row, index) => ( - - - - - {index < rows.length - 1 && } - - ))} - - - - - Add row - - - + + {rows.map((row, index) => ( + + + + + {index < rows.length - 1 && } + + ))} + + + + + Add row + + + + ); } function BoardRow({ rowId, + rowIndex, + rowCount, columns, onRemove, + onMoveUp, + onMoveDown, }: { rowId: string; + rowIndex: number; + rowCount: number; columns: BoardColumnType[]; - onAddComponent?: () => void; onRemove?: (id: string) => void; + onMoveUp?: (id: string) => void; + onMoveDown?: (id: string) => void; }) { const { board, updateBoard } = useBoard(); @@ -102,27 +153,54 @@ function BoardRow({ {columns?.map((column, index) => ( - + {index < columns.length - 1 && } ))} - - + + + + Move row up + + + + Add column + - Remove row + Remove row - + + + Move row down + + ); } From 30c3ba77cc0af1b29873d2825b0c6bbe7fd686fa Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 18 Jan 2026 21:19:24 -0800 Subject: [PATCH 052/412] Add remove column button and fix container height calculation. - Add X button in top right corner of each column to remove it - Fix container height to use MIN_HEIGHT instead of MAX_HEIGHT per row Co-Authored-By: Claude Opus 4.5 --- src/app/(main)/boards/[boardId]/BoardBody.tsx | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/app/(main)/boards/[boardId]/BoardBody.tsx b/src/app/(main)/boards/[boardId]/BoardBody.tsx index e1bc77ad0..75fa780c6 100644 --- a/src/app/(main)/boards/[boardId]/BoardBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardBody.tsx @@ -4,7 +4,7 @@ import { Fragment, type ReactElement } from 'react'; import { Group, Panel, Separator } from 'react-resizable-panels'; import { v4 as uuid } from 'uuid'; import { useBoard } from '@/components/hooks'; -import { ChevronDown, Minus, Plus } from '@/components/icons'; +import { ChevronDown, Minus, Plus, X } from '@/components/icons'; import type { BoardColumn as BoardColumnType } from '@/lib/types'; const CATALOG = { @@ -15,9 +15,6 @@ const CATALOG = { }; const MIN_HEIGHT = 300; -const MAX_HEIGHT = 600; -const MIN_WIDTH = 300; -const MARGIN = 10; const MAX_COLUMNS = 4; export function BoardBody() { @@ -79,8 +76,7 @@ export function BoardBody() { }; const rows = board?.parameters?.rows ?? []; - const rowCount = (rows.length || 1) + 1; - const minHeight = (MAX_HEIGHT + MARGIN) * rowCount; + const minHeight = (rows.length + 1) * MIN_HEIGHT; return ( @@ -149,12 +145,23 @@ function BoardRow({ }); }; + const handleRemoveColumn = (columnId: string) => { + updateBoard({ + parameters: produce(board.parameters, draft => { + const row = draft.rows.find(row => row.id === rowId); + if (row) { + row.columns = row.columns.filter(col => col.id !== columnId); + } + }), + }); + }; + return ( {columns?.map((column, index) => ( - + {index < columns.length - 1 && } @@ -205,7 +212,15 @@ function BoardRow({ ); } -function BoardColumn({ id, component }: { id: string; component?: ReactElement }) { +function BoardColumn({ + id, + component, + onRemove, +}: { + id: string; + component?: ReactElement; + onRemove?: (id: string) => void; +}) { const handleAddComponent = () => {}; return ( @@ -217,7 +232,18 @@ function BoardColumn({ id, component }: { id: string; component?: ReactElement } alignItems="center" justifyContent="center" backgroundColor="3" + position="relative" > + + + + Remove column + + - Remove column - - + {canRemove && ( + + + + Remove column + + + )} + )} + {formatMessage(labels.save)} + + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx new file mode 100644 index 000000000..05e8b357b --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/settings/SharesTable.tsx @@ -0,0 +1,46 @@ +import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; +import { DateDistance } from '@/components/common/DateDistance'; +import { ExternalLink } from '@/components/common/ExternalLink'; +import { useConfig, useMessages } from '@/components/hooks'; +import { ShareDeleteButton } from './ShareDeleteButton'; +import { ShareEditButton } from './ShareEditButton'; + +export function SharesTable(props: DataTableProps) { + const { formatMessage, labels } = useMessages(); + const { cloudMode } = useConfig(); + + const getUrl = (slug: string) => { + if (cloudMode) { + return `${process.env.cloudUrl}/share/${slug}`; + } + return `${window?.location.origin}${process.env.basePath || ''}/share/${slug}`; + }; + + return ( + + + {({ slug }: any) => { + const url = getUrl(slug); + return ( + + {url} + + ); + }} + + + {(row: any) => } + + + {({ id, slug }: any) => { + return ( + + + + + ); + }} + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx index 3970cdbdb..d39c45315 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx @@ -1,14 +1,11 @@ import { Column } from '@umami/react-zen'; import { Panel } from '@/components/common/Panel'; -import { useWebsite } from '@/components/hooks'; import { WebsiteData } from './WebsiteData'; import { WebsiteEditForm } from './WebsiteEditForm'; import { WebsiteShareForm } from './WebsiteShareForm'; import { WebsiteTrackingCode } from './WebsiteTrackingCode'; export function WebsiteSettings({ websiteId }: { websiteId: string; openExternal?: boolean }) { - const website = useWebsite(); - return ( @@ -18,7 +15,7 @@ export function WebsiteSettings({ websiteId }: { websiteId: string; openExternal - + diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx index 56c6f436f..6ac4a4048 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx @@ -1,93 +1,43 @@ -import { - Button, - Column, - Form, - FormButtons, - FormSubmitButton, - IconLabel, - Label, - Row, - Switch, - TextField, -} from '@umami/react-zen'; -import { RefreshCcw } from 'lucide-react'; -import { useState } from 'react'; -import { useConfig, useMessages, useUpdateQuery } from '@/components/hooks'; -import { getRandomChars } from '@/lib/generate'; - -const generateId = () => getRandomChars(16); +import { Button, Column, Heading, Row, Text } from '@umami/react-zen'; +import { Plus } from 'lucide-react'; +import { useApi, useMessages, useModified, useWebsiteSharesQuery } from '@/components/hooks'; +import { SharesTable } from './SharesTable'; export interface WebsiteShareFormProps { websiteId: string; - shareId?: string; - onSave?: () => void; - onClose?: () => void; } -export function WebsiteShareForm({ websiteId, shareId, onSave, onClose }: WebsiteShareFormProps) { - const { formatMessage, labels, messages, getErrorMessage } = useMessages(); - const [currentId, setCurrentId] = useState(shareId); - const { mutateAsync, error, touch, toast } = useUpdateQuery(`/websites/${websiteId}`); - const { cloudMode } = useConfig(); +export function WebsiteShareForm({ websiteId }: WebsiteShareFormProps) { + const { formatMessage, labels, messages } = useMessages(); + const { data, isLoading } = useWebsiteSharesQuery({ websiteId }); + const { post } = useApi(); + const { touch } = useModified(); - const getUrl = (shareId: string) => { - if (cloudMode) { - return `${process.env.cloudUrl}/share/${shareId}`; - } - - return `${window?.location.origin}${process.env.basePath || ''}/share/${shareId}`; + const handleCreate = async () => { + await post(`/websites/${websiteId}/shares`, { parameters: {} }); + touch('shares'); }; - const url = getUrl(currentId); - - const handleGenerate = () => { - setCurrentId(generateId()); - }; - - const handleSwitch = () => { - setCurrentId(currentId ? null : generateId()); - }; - - const handleSave = async () => { - const data = { - shareId: currentId, - }; - await mutateAsync(data, { - onSuccess: async () => { - toast(formatMessage(messages.saved)); - touch(`website:${websiteId}`); - onSave?.(); - onClose?.(); - }, - }); - }; + const shares = data?.data || []; + const hasShares = shares.length > 0; return ( -
- - - {formatMessage(labels.enableShareUrl)} - - {currentId && ( - - - - - - - - - - )} - - - {onClose && } - {formatMessage(labels.save)} - - - -
+ + + {formatMessage(labels.share)} + + + {hasShares ? ( + <> + {formatMessage(messages.shareUrl)} + + + ) : ( + {formatMessage(messages.noDataAvailable)} + )} + ); } diff --git a/src/app/api/share/route.ts b/src/app/api/share/route.ts index 99f5df0ef..a772b4ab4 100644 --- a/src/app/api/share/route.ts +++ b/src/app/api/share/route.ts @@ -1,5 +1,6 @@ import z from 'zod'; import { uuid } from '@/lib/crypto'; +import { getRandomChars } from '@/lib/generate'; import { parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { anyObjectParam } from '@/lib/schema'; @@ -10,7 +11,7 @@ export async function POST(request: Request) { const schema = z.object({ entityId: z.uuid(), shareType: z.coerce.number().int(), - slug: z.string().max(100), + slug: z.string().max(100).optional(), parameters: anyObjectParam, }); @@ -30,7 +31,7 @@ export async function POST(request: Request) { id: uuid(), entityId, shareType, - slug, + slug: slug || getRandomChars(16), parameters, }); diff --git a/src/app/api/websites/[websiteId]/route.ts b/src/app/api/websites/[websiteId]/route.ts index b4c0e7e88..59f314d38 100644 --- a/src/app/api/websites/[websiteId]/route.ts +++ b/src/app/api/websites/[websiteId]/route.ts @@ -1,7 +1,6 @@ import { z } from 'zod'; -import { SHARE_ID_REGEX } from '@/lib/constants'; import { parseRequest } from '@/lib/request'; -import { badRequest, json, ok, serverError, unauthorized } from '@/lib/response'; +import { json, ok, unauthorized } from '@/lib/response'; import { canDeleteWebsite, canUpdateWebsite, canViewWebsite } from '@/permissions'; import { deleteWebsite, getWebsite, updateWebsite } from '@/queries/prisma'; @@ -33,7 +32,6 @@ export async function POST( const schema = z.object({ name: z.string().optional(), domain: z.string().optional(), - shareId: z.string().regex(SHARE_ID_REGEX).nullable().optional(), }); const { auth, body, error } = await parseRequest(request, schema); @@ -43,23 +41,15 @@ export async function POST( } const { websiteId } = await params; - const { name, domain, shareId } = body; + const { name, domain } = body; if (!(await canUpdateWebsite(auth, websiteId))) { return unauthorized(); } - try { - const website = await updateWebsite(websiteId, { name, domain, shareId }); + const website = await updateWebsite(websiteId, { name, domain }); - return Response.json(website); - } catch (e: any) { - if (e.message.toLowerCase().includes('unique constraint') && e.message.includes('share_id')) { - return badRequest({ message: 'That share ID is already taken.' }); - } - - return serverError(e); - } + return Response.json(website); } export async function DELETE( diff --git a/src/app/api/websites/[websiteId]/shares/route.ts b/src/app/api/websites/[websiteId]/shares/route.ts new file mode 100644 index 000000000..db079d497 --- /dev/null +++ b/src/app/api/websites/[websiteId]/shares/route.ts @@ -0,0 +1,74 @@ +import { z } from 'zod'; +import { ENTITY_TYPE } from '@/lib/constants'; +import { uuid } from '@/lib/crypto'; +import { getRandomChars } from '@/lib/generate'; +import { parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { anyObjectParam, filterParams, pagingParams } from '@/lib/schema'; +import { canUpdateWebsite, canViewWebsite } from '@/permissions'; +import { createShare, getSharesByEntityId } from '@/queries/prisma'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + ...filterParams, + ...pagingParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + const { page, pageSize, search } = query; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const data = await getSharesByEntityId(websiteId, { + page, + pageSize, + search, + }); + + return json(data); +} + +export async function POST( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + parameters: anyObjectParam.optional(), + }); + + const { auth, body, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + const { parameters = {} } = body; + + if (!(await canUpdateWebsite(auth, websiteId))) { + return unauthorized(); + } + + const slug = getRandomChars(16); + + const share = await createShare({ + id: uuid(), + entityId: websiteId, + shareType: ENTITY_TYPE.website, + slug, + parameters, + }); + + return json(share); +} diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index e8e5c135e..f47f11f02 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -51,6 +51,7 @@ export * from './queries/useWebsiteSegmentsQuery'; export * from './queries/useWebsiteSessionQuery'; export * from './queries/useWebsiteSessionStatsQuery'; export * from './queries/useWebsiteSessionsQuery'; +export * from './queries/useWebsiteSharesQuery'; export * from './queries/useWebsiteStatsQuery'; export * from './queries/useWebsitesQuery'; export * from './queries/useWebsiteValuesQuery'; diff --git a/src/components/hooks/queries/useWebsiteSharesQuery.ts b/src/components/hooks/queries/useWebsiteSharesQuery.ts new file mode 100644 index 000000000..298e4d264 --- /dev/null +++ b/src/components/hooks/queries/useWebsiteSharesQuery.ts @@ -0,0 +1,20 @@ +import type { ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useModified } from '../useModified'; +import { usePagedQuery } from '../usePagedQuery'; + +export function useWebsiteSharesQuery( + { websiteId }: { websiteId: string }, + options?: ReactQueryOptions, +) { + const { modified } = useModified('shares'); + const { get } = useApi(); + + return usePagedQuery({ + queryKey: ['websiteShares', { websiteId, modified }], + queryFn: pageParams => { + return get(`/websites/${websiteId}/shares`, pageParams); + }, + ...options, + }); +} diff --git a/src/queries/prisma/share.ts b/src/queries/prisma/share.ts index e37dc95b6..53246ffbe 100644 --- a/src/queries/prisma/share.ts +++ b/src/queries/prisma/share.ts @@ -1,14 +1,15 @@ import type { Prisma } from '@/generated/prisma/client'; import prisma from '@/lib/prisma'; +import type { QueryFilters } from '@/lib/types'; export async function findShare(criteria: Prisma.ShareFindUniqueArgs) { return prisma.client.share.findUnique(criteria); } -export async function getShare(entityId: string) { +export async function getShare(shareId: string) { return findShare({ where: { - id: entityId, + id: shareId, }, }); } @@ -21,6 +22,23 @@ export async function getShareByCode(slug: string) { }); } +export async function getSharesByEntityId(entityId: string, filters?: QueryFilters) { + const { pagedQuery } = prisma; + + return pagedQuery( + 'share', + { + where: { + entityId, + }, + orderBy: { + createdAt: 'desc', + }, + }, + filters, + ); +} + export async function createShare( data: Prisma.ShareCreateInput | Prisma.ShareUncheckedCreateInput, ) { From ef3aec09bea636100dd2a2fa801f6cd1357ada6e Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 20 Jan 2026 17:22:16 -0800 Subject: [PATCH 061/412] Add display options form for website shares Allow users to select which navigation items to display when creating or editing a share. Options include traffic, behavior, and growth sections with checkboxes for each nav item (excluding segments/cohorts). Co-Authored-By: Claude Opus 4.5 --- .../[websiteId]/settings/ShareCreateForm.tsx | 83 +++++++++++++++++++ .../[websiteId]/settings/ShareEditForm.tsx | 45 ++++++++-- .../[websiteId]/settings/WebsiteShareForm.tsx | 26 +++--- .../[websiteId]/settings/constants.ts | 30 +++++++ 4 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx create mode 100644 src/app/(main)/websites/[websiteId]/settings/constants.ts diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx new file mode 100644 index 000000000..024fc10b7 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/settings/ShareCreateForm.tsx @@ -0,0 +1,83 @@ +import { + Button, + Checkbox, + Column, + Form, + FormField, + FormSubmitButton, + Row, + Text, +} from '@umami/react-zen'; +import { useState } from 'react'; +import { useApi, useMessages, useModified } from '@/components/hooks'; +import { SHARE_NAV_ITEMS } from './constants'; + +export interface ShareCreateFormProps { + websiteId: string; + onSave?: () => void; + onClose?: () => void; +} + +export function ShareCreateForm({ websiteId, onSave, onClose }: ShareCreateFormProps) { + const { formatMessage, labels } = useMessages(); + const { post } = useApi(); + const { touch } = useModified(); + const [isPending, setIsPending] = useState(false); + + // Build default values - all enabled by default + const defaultValues: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + defaultValues[item.id] = true; + }); + }); + + const handleSubmit = async (data: any) => { + setIsPending(true); + try { + const parameters: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + parameters[item.id] = data[item.id] ?? true; + }); + }); + await post(`/websites/${websiteId}/shares`, { parameters }); + touch('shares'); + onSave?.(); + onClose?.(); + } finally { + setIsPending(false); + } + }; + + return ( +
+ + {SHARE_NAV_ITEMS.map(section => ( + + + {formatMessage((labels as any)[section.section])} + + + {section.items.map(item => ( + + + {formatMessage((labels as any)[item.label])} + + + ))} + + + ))} + + {onClose && ( + + )} + {formatMessage(labels.save)} + + +
+ ); +} diff --git a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx index b1d7d50a5..5e8f8a74e 100644 --- a/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/ShareEditForm.tsx @@ -1,16 +1,20 @@ import { Button, + Checkbox, Column, Form, + FormField, FormSubmitButton, Label, Loading, Row, + Text, TextField, } from '@umami/react-zen'; import { useEffect, useState } from 'react'; import { useApi, useConfig, useMessages, useModified } from '@/components/hooks'; import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; +import { SHARE_NAV_ITEMS } from './constants'; export function ShareEditForm({ shareId, @@ -50,8 +54,15 @@ export function ShareEditForm({ }, [shareId, modified]); const handleSubmit = async (data: any) => { + const parameters: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + parameters[item.id] = data[item.id] ?? true; + }); + }); + await mutateAsync( - { slug: data.slug, parameters: share?.parameters || {} }, + { slug: share.slug, parameters }, { onSuccess: async () => { toast(formatMessage(messages.saved)); @@ -69,24 +80,42 @@ export function ShareEditForm({ const url = getUrl(share?.slug || ''); + // Build default values from share parameters + const defaultValues: Record = {}; + SHARE_NAV_ITEMS.forEach(section => { + section.items.forEach(item => { + defaultValues[item.id] = share?.parameters?.[item.id] ?? true; + }); + }); + return ( -
- + + + {SHARE_NAV_ITEMS.map(section => ( + + + {formatMessage((labels as any)[section.section])} + + + {section.items.map(item => ( + + {formatMessage((labels as any)[item.label])} + + ))} + + + ))} {onClose && ( )} - {formatMessage(labels.save)} + {formatMessage(labels.save)} diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx index 6ac4a4048..7453b4028 100644 --- a/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx +++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx @@ -1,6 +1,8 @@ -import { Button, Column, Heading, Row, Text } from '@umami/react-zen'; +import { Column, Heading, Row, Text } from '@umami/react-zen'; import { Plus } from 'lucide-react'; -import { useApi, useMessages, useModified, useWebsiteSharesQuery } from '@/components/hooks'; +import { useMessages, useWebsiteSharesQuery } from '@/components/hooks'; +import { DialogButton } from '@/components/input/DialogButton'; +import { ShareCreateForm } from './ShareCreateForm'; import { SharesTable } from './SharesTable'; export interface WebsiteShareFormProps { @@ -10,13 +12,6 @@ export interface WebsiteShareFormProps { export function WebsiteShareForm({ websiteId }: WebsiteShareFormProps) { const { formatMessage, labels, messages } = useMessages(); const { data, isLoading } = useWebsiteSharesQuery({ websiteId }); - const { post } = useApi(); - const { touch } = useModified(); - - const handleCreate = async () => { - await post(`/websites/${websiteId}/shares`, { parameters: {} }); - touch('shares'); - }; const shares = data?.data || []; const hasShares = shares.length > 0; @@ -25,10 +20,15 @@ export function WebsiteShareForm({ websiteId }: WebsiteShareFormProps) { {formatMessage(labels.share)} - + } + label={formatMessage(labels.add)} + title={formatMessage(labels.share)} + variant="primary" + width="400px" + > + {({ close }) => } + {hasShares ? ( <> diff --git a/src/app/(main)/websites/[websiteId]/settings/constants.ts b/src/app/(main)/websites/[websiteId]/settings/constants.ts new file mode 100644 index 000000000..f4a3df80f --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/settings/constants.ts @@ -0,0 +1,30 @@ +export const SHARE_NAV_ITEMS = [ + { + section: 'traffic', + items: [ + { id: 'overview', label: 'overview' }, + { id: 'events', label: 'events' }, + { id: 'sessions', label: 'sessions' }, + { id: 'realtime', label: 'realtime' }, + { id: 'compare', label: 'compare' }, + { id: 'breakdown', label: 'breakdown' }, + ], + }, + { + section: 'behavior', + items: [ + { id: 'goals', label: 'goals' }, + { id: 'funnels', label: 'funnels' }, + { id: 'journeys', label: 'journeys' }, + { id: 'retention', label: 'retention' }, + ], + }, + { + section: 'growth', + items: [ + { id: 'utm', label: 'utm' }, + { id: 'revenue', label: 'revenue' }, + { id: 'attribution', label: 'attribution' }, + ], + }, +]; From f2c49845d03e31a0e4321b221dbc509febda7fd5 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 20 Jan 2026 18:12:33 -0800 Subject: [PATCH 062/412] Add filtered navigation to share pages - Update share API to return websiteId and parameters - Create ShareNav component that filters nav items based on parameters - Update SharePage to include navigation sidebar and route to correct page - Support all website pages: overview, events, sessions, realtime, compare, breakdown, goals, funnels, journeys, retention, utm, revenue, attribution Co-Authored-By: Claude Opus 4.5 --- src/app/api/share/[slug]/route.ts | 6 +- src/app/share/[...shareId]/ShareNav.tsx | 143 +++++++++++++++++++++++ src/app/share/[...shareId]/SharePage.tsx | 76 ++++++++++-- src/app/share/[...shareId]/page.tsx | 3 +- 4 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 src/app/share/[...shareId]/ShareNav.tsx diff --git a/src/app/api/share/[slug]/route.ts b/src/app/api/share/[slug]/route.ts index 678795e07..ed3271eab 100644 --- a/src/app/api/share/[slug]/route.ts +++ b/src/app/api/share/[slug]/route.ts @@ -12,7 +12,11 @@ export async function GET(_request: Request, { params }: { params: Promise<{ slu return notFound(); } - const data = { shareId: share.id }; + const data = { + shareId: share.id, + websiteId: share.entityId, + parameters: share.parameters, + }; const token = createToken(data, secret()); return json({ ...data, token }); diff --git a/src/app/share/[...shareId]/ShareNav.tsx b/src/app/share/[...shareId]/ShareNav.tsx new file mode 100644 index 000000000..b494046d4 --- /dev/null +++ b/src/app/share/[...shareId]/ShareNav.tsx @@ -0,0 +1,143 @@ +'use client'; +import { Column } from '@umami/react-zen'; +import { SideMenu } from '@/components/common/SideMenu'; +import { useMessages, useNavigation } from '@/components/hooks'; +import { AlignEndHorizontal, Clock, Eye, Sheet, Tag, User } from '@/components/icons'; +import { Funnel, Lightning, Magnet, Money, Network, Path, Target } from '@/components/svg'; + +export function ShareNav({ + shareId, + parameters, + onItemClick, +}: { + shareId: string; + parameters: Record; + onItemClick?: () => void; +}) { + const { formatMessage, labels } = useMessages(); + const { pathname } = useNavigation(); + + const renderPath = (path: string) => `/share/${shareId}${path}`; + + const allItems = [ + { + section: 'traffic', + label: formatMessage(labels.traffic), + items: [ + { + id: 'overview', + label: formatMessage(labels.overview), + icon: , + path: renderPath(''), + }, + { + id: 'events', + label: formatMessage(labels.events), + icon: , + path: renderPath('/events'), + }, + { + id: 'sessions', + label: formatMessage(labels.sessions), + icon: , + path: renderPath('/sessions'), + }, + { + id: 'realtime', + label: formatMessage(labels.realtime), + icon: , + path: renderPath('/realtime'), + }, + { + id: 'compare', + label: formatMessage(labels.compare), + icon: , + path: renderPath('/compare'), + }, + { + id: 'breakdown', + label: formatMessage(labels.breakdown), + icon: , + path: renderPath('/breakdown'), + }, + ], + }, + { + section: 'behavior', + label: formatMessage(labels.behavior), + items: [ + { + id: 'goals', + label: formatMessage(labels.goals), + icon: , + path: renderPath('/goals'), + }, + { + id: 'funnels', + label: formatMessage(labels.funnels), + icon: , + path: renderPath('/funnels'), + }, + { + id: 'journeys', + label: formatMessage(labels.journeys), + icon: , + path: renderPath('/journeys'), + }, + { + id: 'retention', + label: formatMessage(labels.retention), + icon: , + path: renderPath('/retention'), + }, + ], + }, + { + section: 'growth', + label: formatMessage(labels.growth), + items: [ + { + id: 'utm', + label: formatMessage(labels.utm), + icon: , + path: renderPath('/utm'), + }, + { + id: 'revenue', + label: formatMessage(labels.revenue), + icon: , + path: renderPath('/revenue'), + }, + { + id: 'attribution', + label: formatMessage(labels.attribution), + icon: , + path: renderPath('/attribution'), + }, + ], + }, + ]; + + // Filter items based on parameters + const items = allItems + .map(section => ({ + label: section.label, + items: section.items.filter(item => parameters[item.id] !== false), + })) + .filter(section => section.items.length > 0); + + const selectedKey = items + .flatMap(e => e.items) + .find(({ path }) => path && pathname.endsWith(path.split('?')[0]))?.id; + + return ( + + + + ); +} diff --git a/src/app/share/[...shareId]/SharePage.tsx b/src/app/share/[...shareId]/SharePage.tsx index 7ed066735..3e1cedc06 100644 --- a/src/app/share/[...shareId]/SharePage.tsx +++ b/src/app/share/[...shareId]/SharePage.tsx @@ -1,6 +1,18 @@ 'use client'; -import { Column, useTheme } from '@umami/react-zen'; +import { Column, Grid, useTheme } from '@umami/react-zen'; import { useEffect } from 'react'; +import { AttributionPage } from '@/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage'; +import { BreakdownPage } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage'; +import { FunnelsPage } from '@/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage'; +import { GoalsPage } from '@/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage'; +import { JourneysPage } from '@/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage'; +import { RetentionPage } from '@/app/(main)/websites/[websiteId]/(reports)/retention/RetentionPage'; +import { RevenuePage } from '@/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage'; +import { UTMPage } from '@/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage'; +import { ComparePage } from '@/app/(main)/websites/[websiteId]/compare/ComparePage'; +import { EventsPage } from '@/app/(main)/websites/[websiteId]/events/EventsPage'; +import { RealtimePage } from '@/app/(main)/websites/[websiteId]/realtime/RealtimePage'; +import { SessionsPage } from '@/app/(main)/websites/[websiteId]/sessions/SessionsPage'; import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader'; import { WebsitePage } from '@/app/(main)/websites/[websiteId]/WebsitePage'; import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider'; @@ -8,8 +20,26 @@ import { PageBody } from '@/components/common/PageBody'; import { useShareTokenQuery } from '@/components/hooks'; import { Footer } from './Footer'; import { Header } from './Header'; +import { ShareNav } from './ShareNav'; -export function SharePage({ shareId }) { +const PAGE_COMPONENTS: Record> = { + '': WebsitePage, + overview: WebsitePage, + events: EventsPage, + sessions: SessionsPage, + realtime: RealtimePage, + compare: ComparePage, + breakdown: BreakdownPage, + goals: GoalsPage, + funnels: FunnelsPage, + journeys: JourneysPage, + retention: RetentionPage, + utm: UTMPage, + revenue: RevenuePage, + attribution: AttributionPage, +}; + +export function SharePage({ shareId, path = '' }: { shareId: string; path?: string }) { const { shareToken, isLoading } = useShareTokenQuery(shareId); const { setTheme } = useTheme(); @@ -26,16 +56,42 @@ export function SharePage({ shareId }) { return null; } + const { websiteId, parameters = {} } = shareToken; + + // Check if the requested path is allowed + const pageKey = path || ''; + const isAllowed = pageKey === '' || pageKey === 'overview' || parameters[pageKey] !== false; + + if (!isAllowed) { + return null; + } + + const PageComponent = PAGE_COMPONENTS[pageKey] || WebsitePage; + return ( - -
- - - - -