diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..623e689e1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to Umami + +Thanks for your interest in contributing to Umami! This document outlines the process for contributing code. + +## Branching + +Umami uses the following long-lived branches: + +- `master` — stable, released code. **Do not open PRs against `master`.** +- `dev` — active development. **All pull requests should target `dev`.** + +Feature branches and fixes are merged into `dev`, and `dev` is periodically merged into `master` for releases. + +## Submitting a Pull Request + +1. Fork the repository and create your branch from `dev`: + ```bash + git checkout dev + git pull origin dev + git checkout -b my-feature + ``` +2. Make your changes. Keep PRs focused — one logical change per PR. +3. Ensure the project builds and lints cleanly: + ```bash + pnpm install + pnpm build + pnpm lint + ``` +4. Push your branch and open a pull request **against the `dev` branch**. +5. Fill in the PR description with what changed and why. Link any related issues. + +PRs opened against `master` will be asked to retarget `dev`. + +## Reporting Issues + +- Search [existing issues](https://github.com/umami-software/umami/issues) before opening a new one. +- For bugs, include reproduction steps, expected vs. actual behavior, and your environment (Umami version, database, browser). +- For feature requests, describe the use case before the proposed solution. + +## Development Setup + +See the [README](./README.md) for instructions on installing dependencies, configuring the database, and running Umami locally. + +## License + +By contributing, you agree that your contributions will be licensed under the [MIT License](./LICENSE). diff --git a/db/clickhouse/migrations/11_add_event_session_data_pivot.sql b/db/clickhouse/migrations/11_add_event_session_data_pivot.sql new file mode 100644 index 000000000..2d44cf0bf --- /dev/null +++ b/db/clickhouse/migrations/11_add_event_session_data_pivot.sql @@ -0,0 +1,110 @@ +CREATE TABLE IF NOT EXISTS umami.event_data_pivot +( + website_id UUID, + session_id UUID, + event_id UUID, + event_name LowCardinality(String), + url_path String, + created_at DateTime('UTC'), + property_keys AggregateFunction(groupArray, String), + property_values AggregateFunction(groupArray, String), + property_types AggregateFunction(groupArray, UInt32) +) +ENGINE = AggregatingMergeTree() +PARTITION BY toYYYYMM(created_at) +ORDER BY (website_id, event_name, created_at, event_id) +SETTINGS index_granularity = 8192; + +CREATE MATERIALIZED VIEW IF NOT EXISTS umami.event_data_pivot_mv +TO umami.event_data_pivot +AS SELECT + website_id, + session_id, + event_id, + event_name, + url_path, + created_at, + groupArrayState(data_key) AS property_keys, + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )) AS property_values, + groupArrayState(data_type) AS property_types +FROM umami.event_data +GROUP BY website_id, session_id, event_id, event_name, url_path, created_at; + +-- Backfill existing event data +INSERT INTO umami.event_data_pivot +SELECT + website_id, + session_id, + event_id, + event_name, + url_path, + created_at, + groupArrayState(data_key), + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )), + groupArrayState(data_type) +FROM umami.event_data +GROUP BY website_id, session_id, event_id, event_name, url_path, created_at; + +CREATE TABLE IF NOT EXISTS umami.session_data_pivot +( + website_id UUID, + session_id UUID, + distinct_id String, + created_year_month UInt32, + created_at AggregateFunction(max, DateTime('UTC')), + property_keys AggregateFunction(groupArray, String), + property_values AggregateFunction(groupArray, String), + property_types AggregateFunction(groupArray, UInt32) +) +ENGINE = AggregatingMergeTree() +PARTITION BY created_year_month +ORDER BY (website_id, session_id, distinct_id) +SETTINGS index_granularity = 8192; + +CREATE MATERIALIZED VIEW IF NOT EXISTS umami.session_data_pivot_mv +TO umami.session_data_pivot +AS SELECT + website_id, + session_id, + ifNull(distinct_id, '') AS distinct_id, + toYYYYMM(max(session_data.created_at)) AS created_year_month, + maxState(session_data.created_at) AS created_at, + groupArrayState(data_key) AS property_keys, + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )) AS property_values, + groupArrayState(data_type) AS property_types +FROM umami.session_data +GROUP BY website_id, session_id, distinct_id; + +-- Backfill existing session data +INSERT INTO umami.session_data_pivot +SELECT + website_id, + session_id, + ifNull(distinct_id, '') AS distinct_id, + toYYYYMM(max(session_data.created_at)) AS created_year_month, + maxState(session_data.created_at) AS created_at, + groupArrayState(data_key), + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )), + groupArrayState(data_type) +FROM umami.session_data +GROUP BY website_id, session_id, distinct_id; diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index f8add3569..c5c8dce67 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -305,4 +305,78 @@ CREATE TABLE umami.session_replay ENGINE = MergeTree() PARTITION BY toYYYYMM(created_at) ORDER BY (replay_id, website_id, session_id, visit_id, chunk_index) -SETTINGS index_granularity = 8192; \ No newline at end of file +SETTINGS index_granularity = 8192; + +-- Create event_data_pivot +CREATE TABLE IF NOT EXISTS umami.event_data_pivot +( + website_id UUID, + session_id UUID, + event_id UUID, + event_name LowCardinality(String), + url_path String, + created_at DateTime('UTC'), + property_keys AggregateFunction(groupArray, String), + property_values AggregateFunction(groupArray, String), + property_types AggregateFunction(groupArray, UInt32) +) +ENGINE = AggregatingMergeTree() +PARTITION BY toYYYYMM(created_at) +ORDER BY (website_id, event_name, created_at, event_id) +SETTINGS index_granularity = 8192; + +CREATE MATERIALIZED VIEW IF NOT EXISTS umami.event_data_pivot_mv +TO umami.event_data_pivot +AS SELECT + website_id, + session_id, + event_id, + event_name, + url_path, + created_at, + groupArrayState(data_key) AS property_keys, + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )) AS property_values, + groupArrayState(data_type) AS property_types +FROM umami.event_data +GROUP BY website_id, session_id, event_id, event_name, url_path, created_at; + +-- Create session_data_pivot +CREATE TABLE IF NOT EXISTS umami.session_data_pivot +( + website_id UUID, + session_id UUID, + distinct_id String, + created_year_month UInt32, + created_at AggregateFunction(max, DateTime('UTC')), + property_keys AggregateFunction(groupArray, String), + property_values AggregateFunction(groupArray, String), + property_types AggregateFunction(groupArray, UInt32) +) +ENGINE = AggregatingMergeTree() +PARTITION BY created_year_month +ORDER BY (website_id, session_id, distinct_id) +SETTINGS index_granularity = 8192; + +CREATE MATERIALIZED VIEW IF NOT EXISTS umami.session_data_pivot_mv +TO umami.session_data_pivot +AS SELECT + website_id, + session_id, + ifNull(distinct_id, '') AS distinct_id, + toYYYYMM(max(session_data.created_at)) AS created_year_month, + maxState(session_data.created_at) AS created_at, + groupArrayState(data_key) AS property_keys, + groupArrayState(multiIf( + data_type IN (1, 3, 5), ifNull(string_value, ''), + data_type = 2, toString(ifNull(number_value, 0)), + data_type = 4, toString(ifNull(date_value, toDateTime(0))), + '' + )) AS property_values, + groupArrayState(data_type) AS property_types +FROM umami.session_data +GROUP BY website_id, session_id, distinct_id; diff --git a/package.json b/package.json index 8e6985cd2..db8c39f83 100644 --- a/package.json +++ b/package.json @@ -52,16 +52,15 @@ ], "dependencies": { "@clickhouse/client": "^1.18.2", - "@date-fns/utc": "^1.2.0", + "@date-fns/utc": "^2.1.1", "@dicebear/collection": "^9.4.2", "@dicebear/core": "^9.4.2", - "@hello-pangea/dnd": "^17.0.0", - "@prisma/adapter-pg": "^7.6.0", - "@prisma/client": "^7.6.0", + "@hello-pangea/dnd": "^18.0.1", + "@prisma/adapter-pg": "^7.7.0", + "@prisma/client": "^7.7.0", "@prisma/extension-read-replicas": "^0.5.0", - "@react-spring/web": "^10.0.3", "@svgr/cli": "^8.1.0", - "@tanstack/react-query": "^5.96.0", + "@tanstack/react-query": "^5.99.0", "@umami/react-zen": "^0.245.0", "bcryptjs": "^3.0.2", "chalk": "^5.6.2", @@ -71,88 +70,89 @@ "colord": "^2.9.2", "cors": "^2.8.6", "cross-spawn": "^7.0.3", - "date-fns": "^2.23.0", - "date-fns-tz": "^1.1.4", + "date-fns": "^4.1.0", + "date-fns-tz": "^3.2.0", "debug": "^4.4.3", - "del": "^6.0.0", + "del": "^8.0.1", "detect-browser": "^5.2.0", - "dotenv": "^17.3.1", - "esbuild": "^0.27.4", + "dotenv": "^17.4.2", + "esbuild": "^0.28.0", "immer": "^11.1.4", "ipaddr.js": "^2.3.0", - "is-ci": "^3.0.1", - "is-docker": "^3.0.0", - "is-localhost-ip": "^2.0.0", - "isbot": "^5.1.37", + "is-ci": "^4.1.0", + "is-docker": "^4.0.0", + "is-localhost-ip": "^3.0.1", + "isbot": "^5.1.39", "jsonwebtoken": "^9.0.3", "jszip": "^3.10.1", "kafkajs": "^2.1.0", - "lucide-react": "^1.7.0", - "maxmind": "^5.0.5", + "lucide-react": "^1.8.0", + "maxmind": "^5.0.6", + "motion": "^12.38.0", "next": "16.2.4", - "next-intl": "4.8.3", + "next-intl": "4.9.1", "node-fetch": "^3.2.8", "npm-run-all": "^4.1.5", "papaparse": "^5.5.3", "pg": "^8.20.0", - "prisma": "^7.6.0", - "pure-rand": "^7.0.1", + "prisma": "^7.7.0", + "pure-rand": "^8.4.0", "react": "^19.2.5", "react-dom": "^19.2.5", - "react-error-boundary": "^4.0.4", - "react-resizable-panels": "^4.8.0", - "react-simple-maps": "^2.3.0", + "react-error-boundary": "^6.1.1", + "react-resizable-panels": "^4.10.0", + "react-simple-maps": "^3.0.0", "react-use-measure": "^2.0.4", - "react-window": "^1.8.6", - "redis": "^4.5.1", + "react-window": "^2.2.7", + "redis": "^5.12.1", "request-ip": "^3.3.0", "rrweb": "2.0.0-alpha.4", "rrweb-player": "1.0.0-alpha.4", "semver": "^7.7.4", - "serialize-error": "^12.0.0", - "thenby": "^1.3.4", + "serialize-error": "^13.0.1", + "thenby": "^1.4.0", "ua-parser-js": "^2.0.9", "uuid": "^14.0.0", "zod": "^4.3.6", "zustand": "^5.0.12" }, "devDependencies": { - "@biomejs/biome": "^2.4.10", + "@biomejs/biome": "^2.4.12", "@netlify/plugin-nextjs": "^5.15.9", - "@rollup/plugin-alias": "^5.0.0", - "@rollup/plugin-commonjs": "^25.0.4", + "@rollup/plugin-alias": "^6.0.0", + "@rollup/plugin-commonjs": "^29.0.2", "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.2.0", - "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", "@rollup/plugin-typescript": "^12.3.0", "@types/jest": "^30.0.0", - "@types/node": "^24.12.0", + "@types/node": "^25.6.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.2", "babel-plugin-react-compiler": "19.1.0-rc.2", "cross-env": "^10.1.0", - "cypress": "^13.6.6", + "cypress": "^15.14.0", "dotenv-cli": "^11.0.0", - "jest": "^29.7.0", - "postcss": "^8.5.8", + "jest": "^30.3.0", + "postcss": "^8.5.10", "postcss-flexbugs-fixes": "^5.0.2", - "postcss-import": "^15.1.0", - "postcss-preset-env": "7.8.3", + "postcss-import": "^16.1.1", + "postcss-preset-env": "11.2.1", "prompts": "2.4.2", "rollup": "^4.60.1", "rollup-plugin-copy": "^3.4.0", "rollup-plugin-delete": "^3.0.2", "rollup-plugin-dts": "^6.4.1", - "rollup-plugin-node-externals": "^8.1.1", + "rollup-plugin-node-externals": "^9.0.1", "rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-postcss": "^4.0.2", "tar": "^7.5.13", - "ts-jest": "^29.4.6", - "ts-morph": "^27.0.2", + "ts-jest": "^29.4.9", + "ts-morph": "^28.0.0", "ts-node": "^10.9.1", "tsup": "^8.5.0", "tsx": "^4.19.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f80dc4a6..2e82e501f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.18.2 version: 1.18.2 '@date-fns/utc': - specifier: ^1.2.0 - version: 1.2.0 + specifier: ^2.1.1 + version: 2.1.1 '@dicebear/collection': specifier: ^9.4.2 version: 9.4.2(@dicebear/core@9.4.2) @@ -21,26 +21,23 @@ importers: specifier: ^9.4.2 version: 9.4.2 '@hello-pangea/dnd': - specifier: ^17.0.0 - version: 17.0.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^18.0.1 + version: 18.0.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@prisma/adapter-pg': - specifier: ^7.6.0 - version: 7.6.0 + specifier: ^7.7.0 + version: 7.7.0 '@prisma/client': - specifier: ^7.6.0 - version: 7.6.0(prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3) + specifier: ^7.7.0 + version: 7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3) '@prisma/extension-read-replicas': specifier: ^0.5.0 - version: 0.5.0(@prisma/client@7.6.0(prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)) - '@react-spring/web': - specifier: ^10.0.3 - version: 10.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 0.5.0(@prisma/client@7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3)) '@svgr/cli': specifier: ^8.1.0 - version: 8.1.0(typescript@5.9.3) + version: 8.1.0(typescript@6.0.3) '@tanstack/react-query': - specifier: ^5.96.0 - version: 5.96.0(react@19.2.5) + specifier: ^5.99.0 + version: 5.99.0(react@19.2.5) '@umami/react-zen': specifier: ^0.245.0 version: 0.245.0(@types/react@19.2.14)(immer@11.1.4)(react-aria-components@1.17.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.1.18)(use-sync-external-store@1.6.0(react@19.2.5)) @@ -55,7 +52,7 @@ importers: 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) + version: 3.0.0(chart.js@4.5.1)(date-fns@4.1.0) classnames: specifier: ^2.3.1 version: 2.5.1 @@ -69,26 +66,26 @@ importers: specifier: ^7.0.3 version: 7.0.6 date-fns: - specifier: ^2.23.0 - version: 2.30.0 + specifier: ^4.1.0 + version: 4.1.0 date-fns-tz: - specifier: ^1.1.4 - version: 1.3.8(date-fns@2.30.0) + specifier: ^3.2.0 + version: 3.2.0(date-fns@4.1.0) debug: specifier: ^4.4.3 version: 4.4.3(supports-color@8.1.1) del: - specifier: ^6.0.0 - version: 6.1.1 + specifier: ^8.0.1 + version: 8.0.1 detect-browser: specifier: ^5.2.0 version: 5.3.0 dotenv: - specifier: ^17.3.1 - version: 17.3.1 + specifier: ^17.4.2 + version: 17.4.2 esbuild: - specifier: ^0.27.4 - version: 0.27.4 + specifier: ^0.28.0 + version: 0.28.0 immer: specifier: ^11.1.4 version: 11.1.4 @@ -96,17 +93,17 @@ importers: specifier: ^2.3.0 version: 2.3.0 is-ci: + specifier: ^4.1.0 + version: 4.1.0 + is-docker: + specifier: ^4.0.0 + version: 4.0.0 + is-localhost-ip: specifier: ^3.0.1 version: 3.0.1 - is-docker: - specifier: ^3.0.0 - version: 3.0.0 - is-localhost-ip: - specifier: ^2.0.0 - version: 2.0.0 isbot: - specifier: ^5.1.37 - version: 5.1.37 + specifier: ^5.1.39 + version: 5.1.39 jsonwebtoken: specifier: ^9.0.3 version: 9.0.3 @@ -117,17 +114,20 @@ importers: specifier: ^2.1.0 version: 2.2.4 lucide-react: - specifier: ^1.7.0 - version: 1.7.0(react@19.2.5) + specifier: ^1.8.0 + version: 1.8.0(react@19.2.5) maxmind: - specifier: ^5.0.5 - version: 5.0.5 + specifier: ^5.0.6 + version: 5.0.6 + motion: + specifier: ^12.38.0 + version: 12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next: specifier: 16.2.4 - version: 16.2.4(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 16.2.4(@babel/core@7.29.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-intl: - specifier: 4.8.3 - version: 4.8.3(@swc/helpers@0.5.21)(next@16.2.4(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: 4.9.1 + version: 4.9.1(@swc/helpers@0.5.21)(next@16.2.4(@babel/core@7.29.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.3) node-fetch: specifier: ^3.2.8 version: 3.3.2 @@ -141,11 +141,11 @@ importers: specifier: ^8.20.0 version: 8.20.0 prisma: - specifier: ^7.6.0 - version: 7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + specifier: ^7.7.0 + version: 7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3) pure-rand: - specifier: ^7.0.1 - version: 7.0.1 + specifier: ^8.4.0 + version: 8.4.0 react: specifier: ^19.2.5 version: 19.2.5 @@ -153,23 +153,23 @@ importers: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) react-error-boundary: - specifier: ^4.0.4 - version: 4.1.2(react@19.2.5) + specifier: ^6.1.1 + version: 6.1.1(react@19.2.5) react-resizable-panels: - specifier: ^4.8.0 - version: 4.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^4.10.0 + version: 4.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-simple-maps: - specifier: ^2.3.0 - version: 2.3.0(prop-types@15.8.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^3.0.0 + version: 3.0.0(prop-types@15.8.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-use-measure: specifier: ^2.0.4 version: 2.1.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-window: - specifier: ^1.8.6 - version: 1.8.11(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^2.2.7 + version: 2.2.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5) redis: - specifier: ^4.5.1 - version: 4.7.1 + specifier: ^5.12.1 + version: 5.12.1 request-ip: specifier: ^3.3.0 version: 3.3.0 @@ -183,11 +183,11 @@ importers: specifier: ^7.7.4 version: 7.7.4 serialize-error: - specifier: ^12.0.0 - version: 12.0.0 + specifier: ^13.0.1 + version: 13.0.1 thenby: - specifier: ^1.3.4 - version: 1.3.4 + specifier: ^1.4.0 + version: 1.4.0 ua-parser-js: specifier: ^2.0.9 version: 2.0.9 @@ -202,38 +202,38 @@ importers: version: 5.0.12(@types/react@19.2.14)(immer@11.1.4)(react@19.2.5)(use-sync-external-store@1.6.0(react@19.2.5)) devDependencies: '@biomejs/biome': - specifier: ^2.4.10 - version: 2.4.10 + specifier: ^2.4.12 + version: 2.4.12 '@netlify/plugin-nextjs': specifier: ^5.15.9 version: 5.15.9 '@rollup/plugin-alias': - specifier: ^5.0.0 - version: 5.1.1(rollup@4.60.1) + specifier: ^6.0.0 + version: 6.0.0(rollup@4.60.1) '@rollup/plugin-commonjs': - specifier: ^25.0.4 - version: 25.0.8(rollup@4.60.1) + specifier: ^29.0.2 + version: 29.0.2(rollup@4.60.1) '@rollup/plugin-json': specifier: ^6.0.0 version: 6.1.0(rollup@4.60.1) '@rollup/plugin-node-resolve': - specifier: ^15.2.0 - version: 15.3.1(rollup@4.60.1) + specifier: ^16.0.3 + version: 16.0.3(rollup@4.60.1) '@rollup/plugin-replace': - specifier: ^5.0.2 - version: 5.0.7(rollup@4.60.1) + specifier: ^6.0.3 + version: 6.0.3(rollup@4.60.1) '@rollup/plugin-terser': - specifier: ^0.4.4 - version: 0.4.4(rollup@4.60.1) + specifier: ^1.0.0 + version: 1.0.0(rollup@4.60.1) '@rollup/plugin-typescript': specifier: ^12.3.0 - version: 12.3.0(rollup@4.60.1)(tslib@2.8.1)(typescript@5.9.3) + version: 12.3.0(rollup@4.60.1)(tslib@2.8.1)(typescript@6.0.3) '@types/jest': specifier: ^30.0.0 version: 30.0.0 '@types/node': - specifier: ^24.12.0 - version: 24.12.0 + specifier: ^25.6.0 + version: 25.6.0 '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -247,26 +247,26 @@ importers: specifier: ^10.1.0 version: 10.1.0 cypress: - specifier: ^13.6.6 - version: 13.17.0 + specifier: ^15.14.0 + version: 15.14.0 dotenv-cli: specifier: ^11.0.0 version: 11.0.0 jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) + specifier: ^30.3.0 + version: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) postcss: - specifier: ^8.5.8 - version: 8.5.8 + specifier: ^8.5.10 + version: 8.5.10 postcss-flexbugs-fixes: specifier: ^5.0.2 - version: 5.0.2(postcss@8.5.8) + version: 5.0.2(postcss@8.5.10) postcss-import: - specifier: ^15.1.0 - version: 15.1.0(postcss@8.5.8) + specifier: ^16.1.1 + version: 16.1.1(postcss@8.5.10) postcss-preset-env: - specifier: 7.8.3 - version: 7.8.3(postcss@8.5.8) + specifier: 11.2.1 + version: 11.2.1(postcss@8.5.10) prompts: specifier: 2.4.2 version: 2.4.2 @@ -281,37 +281,37 @@ importers: version: 3.0.2(rollup@4.60.1) rollup-plugin-dts: specifier: ^6.4.1 - version: 6.4.1(rollup@4.60.1)(typescript@5.9.3) + version: 6.4.1(rollup@4.60.1)(typescript@6.0.3) rollup-plugin-node-externals: - specifier: ^8.1.1 - version: 8.1.2(rollup@4.60.1) + specifier: ^9.0.1 + version: 9.0.1(rollup@4.60.1) rollup-plugin-peer-deps-external: specifier: ^2.2.4 version: 2.2.4(rollup@4.60.1) rollup-plugin-postcss: specifier: ^4.0.2 - version: 4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) + version: 4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) tar: specifier: ^7.5.13 version: 7.5.13 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.27.4)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)))(typescript@5.9.3) + specifier: ^29.4.9 + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.28.0)(jest-util@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)))(typescript@6.0.3) ts-morph: - specifier: ^27.0.2 - version: 27.0.2 + specifier: ^28.0.0 + version: 28.0.0 ts-node: specifier: ^10.9.1 - version: 10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3) + version: 10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3) tsup: specifier: ^8.5.0 - version: 8.5.1(@swc/core@1.15.11(@swc/helpers@0.5.21))(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) + version: 8.5.1(@swc/core@1.15.26(@swc/helpers@0.5.21))(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.1) tsx: specifier: ^4.19.0 version: 4.21.0 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages: @@ -331,18 +331,34 @@ packages: resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + '@babel/core@7.28.3': resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} engines: {node: '>=6.9.0'} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} @@ -351,14 +367,24 @@ packages: resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': @@ -381,11 +407,20 @@ packages: resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.28.3': resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-syntax-async-generators@7.8.4': resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -407,8 +442,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -423,8 +458,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -471,80 +506,92 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.3': - resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.3': resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.2': resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@biomejs/biome@2.4.10': - resolution: {integrity: sha512-xxA3AphFQ1geij4JTHXv4EeSTda1IFn22ye9LdyVPoJU19fNVl0uzfEuhsfQ4Yue/0FaLs2/ccVi4UDiE7R30w==} + '@biomejs/biome@2.4.12': + resolution: {integrity: sha512-Rro7adQl3NLq/zJCIL98eElXKI8eEiBtoeu5TbXF/U3qbjuSc7Jb5rjUbeHHcquDWeSf3HnGP7XI5qGrlRk/pA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.4.10': - resolution: {integrity: sha512-vuzzI1cWqDVzOMIkYyHbKqp+AkQq4K7k+UCXWpkYcY/HDn1UxdsbsfgtVpa40shem8Kax4TLDLlx8kMAecgqiw==} + '@biomejs/cli-darwin-arm64@2.4.12': + resolution: {integrity: sha512-BnMU4Pc3ciEVteVpZ0BK33MLr7X57F5w1dwDLDn+/iy/yTrA4Q/N2yftidFtsA4vrDh0FMXDpacNV/Tl3fbmng==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.10': - resolution: {integrity: sha512-14fzASRo+BPotwp7nWULy2W5xeUyFnTaq1V13Etrrxkrih+ez/2QfgFm5Ehtf5vSjtgx/IJycMMpn5kPd5ZNaA==} + '@biomejs/cli-darwin-x64@2.4.12': + resolution: {integrity: sha512-x9uJ0bI1rJsWICp3VH8w/5PnAVD3A7SqzDpbrfoUQX1QyWrK5jSU4fRLo/wSgGeplCivbxBRKmt5Xq4/nWvq8A==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.4.10': - resolution: {integrity: sha512-WrJY6UuiSD/Dh+nwK2qOTu8kdMDlLV3dLMmychIghHPAysWFq1/DGC1pVZx8POE3ZkzKR3PUUnVrtZfMfaJjyQ==} + '@biomejs/cli-linux-arm64-musl@2.4.12': + resolution: {integrity: sha512-FhfpkAAlKL6kwvcVap0Hgp4AhZmtd3YImg0kK1jd7C/aSoh4SfsB2f++yG1rU0lr8Y5MCFJrcSkmssiL9Xnnig==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.4.10': - resolution: {integrity: sha512-7MH1CMW5uuxQ/s7FLST63qF8B3Hgu2HRdZ7tA1X1+mk+St4JOuIrqdhIBnnyqeyWJNI+Bww7Es5QZ0wIc1Cmkw==} + '@biomejs/cli-linux-arm64@2.4.12': + resolution: {integrity: sha512-tOwuCuZZtKi1jVzbk/5nXmIsziOB6yqN8c9r9QM0EJYPU6DpQWf11uBOSCfFKKM4H3d9ZoarvlgMfbcuD051Pw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.4.10': - resolution: {integrity: sha512-kDTi3pI6PBN6CiczsWYOyP2zk0IJI08EWEQyDMQWW221rPaaEz6FvjLhnU07KMzLv8q3qSuoB93ua6inSQ55Tw==} + '@biomejs/cli-linux-x64-musl@2.4.12': + resolution: {integrity: sha512-dwTIgZrGutzhkQCuvHynCkyW6hJxUuyZqKKO0YNfaS2GUoRO+tOvxXZqZB6SkWAOdfZTzwaw8IEdUnIkHKHoew==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.4.10': - resolution: {integrity: sha512-tZLvEEi2u9Xu1zAqRjTcpIDGVtldigVvzug2fTuPG0ME/g8/mXpRPcNgLB22bGn6FvLJpHHnqLnwliOu8xjYrg==} + '@biomejs/cli-linux-x64@2.4.12': + resolution: {integrity: sha512-8pFeAnLU9QdW9jCIslB/v82bI0lhBmz2ZAKc8pVMFPO0t0wAHsoEkrUQUbMkIorTRIjbqyNZHA3lEXavsPWYSw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.4.10': - resolution: {integrity: sha512-umwQU6qPzH+ISTf/eHyJ/QoQnJs3V9Vpjz2OjZXe9MVBZ7prgGafMy7yYeRGnlmDAn87AKTF3Q6weLoMGpeqdQ==} + '@biomejs/cli-win32-arm64@2.4.12': + resolution: {integrity: sha512-B0DLnx0vA9ya/3v7XyCaP+/lCpnbWbMOfUFFve+xb5OxyYvdHaS55YsSddr228Y+JAFk58agCuZTsqNiw2a6ig==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.4.10': - resolution: {integrity: sha512-aW/JU5GuyH4uxMrNYpoC2kjaHlyJGLgIa3XkhPEZI0uKhZhJZU8BuEyJmvgzSPQNGozBwWjC972RaNdcJ9KyJg==} + '@biomejs/cli-win32-x64@2.4.12': + resolution: {integrity: sha512-yMckRzTyZ83hkk8iDFWswqSdU8tvZxspJKnYNh7JZr/zhZNOlzH13k4ecboU6MurKExCe2HUkH75pGI/O2JwGA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -562,113 +609,331 @@ packages: resolution: {integrity: sha512-fuquQswRSHWM6D079ZeuGqkMOsqtcUPL06UdTnowmoeeYjVrqisfVmvnw8pc3OeKS4kVb91oygb/MfLDiMs0TQ==} engines: {node: '>=16'} - '@colors/colors@1.5.0': - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@csstools/postcss-cascade-layers@1.1.1': - resolution: {integrity: sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/cascade-layer-name-parser@3.0.0': + resolution: {integrity: sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/postcss-color-function@1.1.1': - resolution: {integrity: sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.0': + resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/postcss-font-format-keywords@1.0.1': - resolution: {integrity: sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/css-color-parser@4.1.0': + resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/postcss-hwb-function@1.0.2': - resolution: {integrity: sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/postcss-ic-unit@1.0.1': - resolution: {integrity: sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@csstools/media-query-list-parser@5.0.0': + resolution: {integrity: sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/postcss-is-pseudo-class@2.0.7': - resolution: {integrity: sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-alpha-function@2.0.4': + resolution: {integrity: sha512-fti7+GybzvfMrv5TSU6x8rWtXWOth5nLefT5w5AKJ3F3T0bZoxlRqajF0ZUgTtnytfMd4dQ8n5UiaNmsjFA65A==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-nested-calc@1.0.0': - resolution: {integrity: sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-cascade-layers@6.0.0': + resolution: {integrity: sha512-WhsECqmrEZQGqaPlBA7JkmF/CJ2/+wetL4fkL9sOPccKd32PQ1qToFM6gqSI5rkpmYqubvbxjEJhyMTHYK0vZQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-normalize-display-values@1.0.1': - resolution: {integrity: sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-color-function-display-p3-linear@2.0.3': + resolution: {integrity: sha512-u8QNV2TKOxG6cqK4ZrJkpctnxdrwdNTMrkyokmCi+iuLpJegOraA0cqC7HoxF2tHhxjuXc+BxwY/Qd62SwvanQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-oklab-function@1.1.1': - resolution: {integrity: sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-color-function@5.0.3': + resolution: {integrity: sha512-BiBukIeQ7rPjx9A//9+qgJugBjX6FY9eWiojbnfIJCPulWrl8J07rCgQbFkloTXena+a6Aw5xa25weU+3MA75A==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-progressive-custom-properties@1.3.0': - resolution: {integrity: sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-color-mix-function@4.0.3': + resolution: {integrity: sha512-M8ju3iqHRXtW1/5HYuOmi9WFR5rGGFgqkPh+kXkv/eG56oYK/WYtTeIwJgdcro7lRwjlo4Ut8xqbV3Iovkwfrw==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.3 + postcss: ^8.4 - '@csstools/postcss-stepped-value-functions@1.0.1': - resolution: {integrity: sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-color-mix-variadic-function-arguments@2.0.3': + resolution: {integrity: sha512-tL46UyFjIjz7mDywoPOe/JgOpvMic0rsTUfdMBB1OHrUcCtE8MQpBILzYl/cAOtinJGu+ZQLuDhqTgTBOoeg3g==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-text-decoration-shorthand@1.0.0': - resolution: {integrity: sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-content-alt-text@3.0.0': + resolution: {integrity: sha512-OHa+4aCcrJtHpPWB3zptScHwpS1TUbeLR4uO0ntIz0Su/zw9SoWkVu+tDMSySSAsNtNSI3kut4fTliFwIsrHxA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-trigonometric-functions@1.0.2': - resolution: {integrity: sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==} - engines: {node: ^14 || >=16} + '@csstools/postcss-contrast-color-function@3.0.3': + resolution: {integrity: sha512-YcohXq+/hfYeobKirg3oXGivDaaTfOPv568bE3jYQCn9ILpFz+RgyJR/kF7ZWh5560TTlTjeCqF4ZmVsj2zwnw==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/postcss-unset-value@1.0.2': - resolution: {integrity: sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==} - engines: {node: ^12 || ^14 || >=16} + '@csstools/postcss-exponential-functions@3.0.2': + resolution: {integrity: sha512-WDrfdFJXF4M67+wniEGr/5XVzsmn1rt2lL1YAlTfE7x7XDlRstTc5e+HuFoGv6jkiMWTwPsiADJaLwsnGC3UjQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - '@csstools/selector-specificity@2.2.0': - resolution: {integrity: sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==} - engines: {node: ^14 || ^16 || >=18} + '@csstools/postcss-font-format-keywords@5.0.0': + resolution: {integrity: sha512-M1EjCe/J3u8fFhOZgRci74cQhJ7R0UFBX6T+WqoEvjrr8hVfMiV+HTYrzxLY5OW8YllvXYr5Q5t5OvJbsUSeDg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss-selector-parser: ^6.0.10 + postcss: ^8.4 - '@cypress/request@3.0.9': - resolution: {integrity: sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==} + '@csstools/postcss-font-width-property@1.0.0': + resolution: {integrity: sha512-AvmySApdijbjYQuXXh95tb7iVnqZBbJrv3oajO927ksE/mDmJBiszm+psW8orL2lRGR8j6ZU5Uv9/ou2Z5KRKA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-gamut-mapping@3.0.3': + resolution: {integrity: sha512-3v5ZvcVuynhFh5qCJX2LIJ9Iry8/SvxfOEj6vDngNxbH/3OKTZBFLgK+DgLuIbsP1DLA9LLH3Rn7jmRxXgEDLA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-gradients-interpolation-method@6.0.3': + resolution: {integrity: sha512-wrRIaRv1dkq30a8nvYWtSAf41bwCl+sVzLBKGnqeOwk81aSktKN3NattJpkiPyoOtEoFqChisl3WH3Csj/rOsw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-hwb-function@5.0.3': + resolution: {integrity: sha512-bHz0uc/PBg2wJEAlGinUf494nMyuXsVKH/fExc2xGkvL6WHOKlxzx/lkn+2AVCQACtWBLVRCBDgDnkYr4RSC9w==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-ic-unit@5.0.0': + resolution: {integrity: sha512-/ws5d6c4uKqfM9zIL3ugcGI+3fvZEOOkJHNzAyTAGJIdZ+aSL9BVPNlHGV4QzmL0vqBSCOdU3+rhcMEj3+KzYw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-initial@3.0.0': + resolution: {integrity: sha512-UVUrFmrTQyLomVepnjWlbBg7GoscLmXLwYFyjbcEnmpeGW7wde6lNpx5eM3eVwZI2M+7hCE3ykYnAsEPLcLa+Q==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-is-pseudo-class@6.0.0': + resolution: {integrity: sha512-1Hdy/ykg9RDo8vU8RiM2o+RaXO39WpFPaIkHxlAEJFofle/lc33tdQMKhBk3jR/Fe+uZNLOs3HlowFafyFptVw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-light-dark-function@3.0.0': + resolution: {integrity: sha512-s++V5/hYazeRUCYIn2lsBVzUsxdeC46gtwpgW6lu5U/GlPOS5UTDT14kkEyPgXmFbCvaWLREqV7YTMJq1K3G6w==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-float-and-clear@4.0.0': + resolution: {integrity: sha512-NGzdIRVj/VxOa/TjVdkHeyiJoDihONV0+uB0csUdgWbFFr8xndtfqK8iIGP9IKJzco+w0hvBF2SSk2sDSTAnOQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-overflow@3.0.0': + resolution: {integrity: sha512-5cRg93QXVskM0MNepHpPcL0WLSf5Hncky0DrFDQY/4ozbH5lH7SX5ejayVpNTGSX7IpOvu7ykQDLOdMMGYzwpA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-overscroll-behavior@3.0.0': + resolution: {integrity: sha512-82Jnl/5Wi5jb19nQE1XlBHrZcNL3PzOgcj268cDkfwf+xi10HBqufGo1Unwf5n8bbbEFhEKgyQW+vFsc9iY1jw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-resize@4.0.0': + resolution: {integrity: sha512-L0T3q0gei/tGetCGZU0c7VN77VTivRpz1YZRNxjXYmW+85PKeI6U9YnSvDqLU2vBT2uN4kLEzfgZ0ThIZpN18A==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-viewport-units@4.0.0': + resolution: {integrity: sha512-TA3AqVN/1IH3dKRC2UUWvprvwyOs2IeD7FDZk5Hz20w4q33yIuSg0i0gjyTUkcn90g8A4n7QpyZ2AgBrnYPnnA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-media-minmax@3.0.2': + resolution: {integrity: sha512-+ABxs2ZhJDhy+B9PJg7pgkGq6/d3XPXsWl7+6yZfAk4b2ba6aQ1h2AiTn04XwS6rpMpZEF3tONli/ubfu4y8AQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-media-queries-aspect-ratio-number-values@4.0.0': + resolution: {integrity: sha512-FDdC3lbrj8Vr0SkGIcSLTcRB7ApG6nlJFxOxkEF2C5hIZC1jtgjISFSGn/WjFdVkn8Dqe+Vx9QXI3axS2w1XHw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-mixins@1.0.0': + resolution: {integrity: sha512-rz6qjT2w9L3k65jGc2dX+3oGiSrYQ70EZPDrINSmSVoVys7lLBFH0tvEa8DW2sr9cbRVD/W+1sy8+7bfu0JUfg==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-nested-calc@5.0.0': + resolution: {integrity: sha512-aPSw8P60e/i9BEfugauhikBqgjiwXcw3I9o4vXs+hktl4NSTgZRI0QHimxk9mst8N01A2TKDBxOln3mssRxiHQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-normalize-display-values@5.0.1': + resolution: {integrity: sha512-FcbEmoxDEGYvm2W3rQzVzcuo66+dDJjzzVDs+QwRmZLHYofGmMGwIKPqzF86/YW+euMDa7sh1xjWDvz/fzByZQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-oklab-function@5.0.3': + resolution: {integrity: sha512-vTMgJFMwMt9gnPvhKaDnMR7E/h9Nb+rPUv825SY5VUo4PWj+w0OH/N2NqgvjYeubaA3BVckbKDlvADATRpD4Hw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-position-area-property@2.0.0': + resolution: {integrity: sha512-TeEfzsJGB23Syv7yCm8AHCD2XTFujdjr9YYu9ebH64vnfCEvY4BG319jXAYSlNlf3Yc9PNJ6WnkDkUF5XVgSKQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-progressive-custom-properties@5.0.0': + resolution: {integrity: sha512-NsJoZ89rxmDrUsITf8QIk5w+lQZQ8Xw5K6cLFG+cfiffsLYHb3zcbOOrHLetGl1WIhjWWQ4Cr8MMrg46Q+oACg==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-property-rule-prelude-list@2.0.0': + resolution: {integrity: sha512-qcMAkc9AhpzHgmQCD8hoJgGYifcOAxd1exXjjxilMM6euwRE619xDa4UsKBCv/v4g+sS63sd6c29LPM8s2ylSQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-random-function@3.0.2': + resolution: {integrity: sha512-iQ3vfX1LIqRXX7P1/ol45EpJ5CTWdQCAfdpTlHlsRPU4jMQeepmeNjQ0F60bj8RWTS1RkJ318fzzq4mUlyZ7hA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-relative-color-syntax@4.0.3': + resolution: {integrity: sha512-SZSImz4KufmLi0dRwYivWXlza+7HF84SRApY8R48SyWgn+f0gDvmCn7D2Ie4CED7qU0JJK+YfCUC1HVlaQ10dg==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-scope-pseudo-class@5.0.0': + resolution: {integrity: sha512-kBrBFJcAji3MSHS4qQIihPvJfJC5xCabXLbejqDMiQi+86HD4eMBiTayAo46Urg7tlEmZZQFymFiJt+GH6nvXw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-sign-functions@2.0.2': + resolution: {integrity: sha512-vOxkkMCMVnyaj7CW03uKR2R/zhJaCrptsXlm31HgI/dqC1lSIGnmu5W7N68x23XwcSgc8fE/fg0jKj4x1XFH4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-stepped-value-functions@5.0.2': + resolution: {integrity: sha512-4PtqkRoBcMSxZG00gcDv+nq7cxVUua+Yd7TmG16qzJjdolyICHkx1RfhNL5mKSnWOLxUnk/IdxAoWN+KU7E/ng==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-syntax-descriptor-syntax-production@2.0.0': + resolution: {integrity: sha512-elYcbdiBXAkPqvojB9kIBRuHY6htUhjSITtFQ+XiXnt6SvZCbNGxQmaaw6uZ7SPHu/+i/XVjzIt09/1k3SIerQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-system-ui-font-family@2.0.0': + resolution: {integrity: sha512-FyGZCgchFImFyiHS2x3rD5trAqatf/x23veBLTIgbaqyFfna6RNBD+Qf8HRSjt6HGMXOLhAjxJ3OoZg0bbn7Qw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-text-decoration-shorthand@5.0.3': + resolution: {integrity: sha512-62fjggvIM1YYfDJPcErMUDkEZB6CByG8neTJqexnZe1hRBgCjD4dnXDLoCSSurjs1LzjBq6irFDpDaOvDZfrlw==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-trigonometric-functions@5.0.2': + resolution: {integrity: sha512-hRansZmQk1HH11WGUNlWy8H/DCB9Wy6zDbRcyBfF2UUP+V2fubK+qwmq0q6LIDje5gRzxlKyWhgFYxPy1ohivA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-unset-value@5.0.0': + resolution: {integrity: sha512-EoO54sS2KCIfesvHyFYAW99RtzwHdgaJzhl7cqKZSaMYKZv3fXSOehDjAQx8WZBKn1JrMd7xJJI1T1BxPF7/jA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-resolve-nested@4.0.0': + resolution: {integrity: sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 + + '@csstools/selector-specificity@6.0.0': + resolution: {integrity: sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 + + '@csstools/utilities@3.0.0': + resolution: {integrity: sha512-etDqA/4jYvOGBM6yfKCOsEXfH96BKztZdgGmGqKi2xHnDe0ILIBraRspwgYatJH9JsCZ5HCGoCst8w18EKOAdg==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 + + '@cypress/request@3.0.10': + resolution: {integrity: sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==} engines: {node: '>= 6'} '@cypress/xvfb@1.2.4': resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} - '@date-fns/utc@1.2.0': - resolution: {integrity: sha512-YLq+crMPJiBmIdkRmv9nZuZy1mVtMlDcUKlg4mvI0UsC/dZeIaGoGB5p/C4FrpeOhZ7zBTK03T58S0DFkRNMnw==} + '@date-fns/utc@2.1.1': + resolution: {integrity: sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA==} '@dicebear/adventurer-neutral@9.4.2': resolution: {integrity: sha512-5xgkG/mNL4j3Q4SJGQLBU/KnU90tng8Ze5ofThD+55wi0oeY/nSAUowg6UFCmHrktjifj/MEx3CQqbpcPWtfIA==} @@ -880,191 +1145,350 @@ packages: '@electric-sql/pglite@0.4.1': resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.9.2': resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@formatjs/bigdecimal@0.2.0': - resolution: {integrity: sha512-GeaxHZbUoYvHL9tC5eltHLs+1zU70aPw0s7LwqgktIzF5oMhNY4o4deEtusJMsq7WFJF3Ye2zQEzdG8beVk73w==} + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - '@formatjs/ecma402-abstract@3.2.0': - resolution: {integrity: sha512-dHnqHgBo6GXYGRsepaE1wmsC2etaivOWd5VaJstZd+HI2zR3DCUjbDVZRtoPGkkXZmyHvBwrdEUuqfvzhF/DtQ==} + '@formatjs/fast-memoize@3.1.2': + resolution: {integrity: sha512-vPnriihkfK0lzoQGaXq+qXH23VsYyansRTkTgo2aTG0k1NjLFyZimFVdfj4C9JkSE5dm7CEngcQ5TTc1yAyBfQ==} - '@formatjs/fast-memoize@3.1.1': - resolution: {integrity: sha512-CbNbf+tlJn1baRnPkNePnBqTLxGliG6DDgNa/UtV66abwIjwsliPMOt0172tzxABYzSuxZBZfcp//qI8AvBWPg==} + '@formatjs/icu-messageformat-parser@3.5.4': + resolution: {integrity: sha512-JVY39ROgLt+pIYngo6piyj4OVfZmXs/2FkC4wLS+ql1Eig/sGJKB7YwDO/5bkJFkfwaFAeIpgEiJc8hiYxNalw==} - '@formatjs/icu-messageformat-parser@3.5.3': - resolution: {integrity: sha512-HJWZ9S6JWey6iY5+YXE3Kd0ofWU1sC2KTTp56e1168g/xxWvVvr8k9G4fexIgwYV9wbtjY7kGYK5FjoWB3B2OQ==} + '@formatjs/icu-skeleton-parser@2.1.4': + resolution: {integrity: sha512-8bSFZbrlvGX11ywMZxtgkPBt5Q8/etyts7j7j+GWpOVK1g43zwMIH3LZxk43HAtEP7L/jtZ+OZaMiFTOiBj9CA==} - '@formatjs/icu-skeleton-parser@2.1.3': - resolution: {integrity: sha512-9mFp8TJ166ZM2pcjKwsBWXrDnOJGT7vMEScVgLygUODPOsE8S6f/FHoacvrlHK1B4dYZk8vSCNruyPU64AfgJQ==} + '@formatjs/intl-localematcher@0.8.3': + resolution: {integrity: sha512-pHUjWb9NuhnMs8+PxQdzBtZRFJHlGhrURGAbm6Ltwl82BFajeuiIR3jblSa7ia3r62rXe/0YtVpUG3xWr5bFCA==} - '@formatjs/intl-localematcher@0.8.2': - resolution: {integrity: sha512-q05KMYGJLyqFNFtIb8NhWLF5X3aK/k0wYt7dnRFuy6aLQL+vUwQ1cg5cO4qawEiINybeCPXAWlprY2mSBjSXAQ==} - - '@hello-pangea/dnd@17.0.0': - resolution: {integrity: sha512-LDDPOix/5N0j5QZxubiW9T0M0+1PR0rTDWeZF5pu1Tz91UQnuVK4qQ/EjY83Qm2QeX0eM8qDXANfDh3VVqtR4Q==} + '@hello-pangea/dnd@18.0.1': + resolution: {integrity: sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 '@hono/node-server@1.19.11': resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} @@ -1221,14 +1645,6 @@ packages: '@internationalized/string@3.2.8': resolution: {integrity: sha512-NdbMQUSfXLYIQol5VyMtinm9pZDciiMfN7RtmSuSB78io1hqwJ0naYfxyW6vgxWBkzWymQa/3uLDlbfmshtCaA==} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1241,17 +1657,17 @@ packages: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} engines: {node: '>=8'} - '@jest/console@29.7.0': - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/core@29.7.0': - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -1262,79 +1678,83 @@ packages: resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/environment@29.7.0': - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect-utils@29.7.0': - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect-utils@30.1.1': resolution: {integrity: sha512-5YUHr27fpJ64dnvtu+tt11ewATynrHkGYD+uSFgRr8V2eFJis/vEXgToyLwccIwqBihVfz9jwio+Zr1ab1Zihw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect@29.7.0': - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/fake-timers@29.7.0': - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/get-type@30.1.0': resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/globals@29.7.0': - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/pattern@30.0.1': resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/reporters@29.7.0': - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/schemas@30.0.5': resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/source-map@29.6.3': - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-result@29.7.0': - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-sequencer@29.7.0': - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/types@30.0.5': resolution: {integrity: sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1363,6 +1783,9 @@ packages: '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@netlify/plugin-nextjs@5.15.9': resolution: {integrity: sha512-4kJvV+wrt4/ncehfaOXfhv1FYKCv9EFjq6/tgXXYSlqPDcbsuTXR0DTz9IvyZ/CpPRadRD/zzIqD9wXgCmA2lg==} engines: {node: '>=18.0.0'} @@ -1516,14 +1939,18 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@prisma/adapter-pg@7.6.0': - resolution: {integrity: sha512-BjHNmJqqa42NqJSDPnXUfwUofWo8LJY7Ui2gqxN4DmAOb+H/gGKv+hln2Xq/1kSJXPW5AXMXuNiPDMpywvyIOw==} + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@prisma/client-runtime-utils@7.6.0': - resolution: {integrity: sha512-fD7jlqubsZvVODKvsp9lOpXVecx2aWGxC2l35Ioz2t+teUJ5CfR0SAMsi7UkU1VvaZmmm+DS6BdujF622nY7tQ==} + '@prisma/adapter-pg@7.7.0': + resolution: {integrity: sha512-q33Ta8sKbgzEpAy0lx45tAq//yMv0qcb+8nj+TCA3P4wiAY+OBFEFk/NDkZncAfHaNJeGo5WJpJdpbL+ijYx8g==} - '@prisma/client@7.6.0': - resolution: {integrity: sha512-7Pe/1ayh3GgWPEg4mmT4ax77LJ1wC+XlnIFvQ94bLP2DsUnOpnruQQR3Jw7r+Frthk94QqDNxo3FjSg8h9PXeQ==} + '@prisma/client-runtime-utils@7.7.0': + resolution: {integrity: sha512-BLyd0UpFYOtyJFTHm7jS9vesHW7P83abibodQMiIofqjBKzDHQ1VAsQkdfvXyYDkPlONPfOTz7/rv3x/+CQqvQ==} + + '@prisma/client@7.7.0': + resolution: {integrity: sha512-5Ar4OsZpJ54s21sy5oDNNW9gQtd4NuxCaiM7+JDTOU07D6VvlpLjYzAVCMB1+JzokN+08dAVomlx+b7bhJd3ww==} engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' @@ -1534,40 +1961,40 @@ packages: typescript: optional: true - '@prisma/config@7.6.0': - resolution: {integrity: sha512-MuAz1MK4PeG5/03YzfzX3CnFVHQ6qePGwUpQRzPzX5tT0ffJ3Tzi9zJZbBc+VzEGFCM8ghW/gTVDR85Syjt+Yw==} + '@prisma/config@7.7.0': + resolution: {integrity: sha512-hmPI3tKLO2aP0Y5vugbjcnA9qqlfJndiT6ds4tw28U5hNHLWg+mHJEWAhjsSPgxjtmxhJ/EDIeIlyh+3Us0OPg==} '@prisma/debug@7.2.0': resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} - '@prisma/debug@7.6.0': - resolution: {integrity: sha512-LpHr3qos4lQZ6sxwjStf59YBht7m9/QF7NSQsMH6qGENWZu2w3UkQUGn1h5iRkDjnWRj3VHykOu9qFhps4ADvA==} + '@prisma/debug@7.7.0': + resolution: {integrity: sha512-12J62XdqCmpiwJHhHdQxZeY3ckVCWIFmcJP8hg5dPTceeiQ0wiojXGFYTluKqFQfu46fRLgb/rLALZMAx3+dTA==} '@prisma/dev@0.24.3': resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} - '@prisma/driver-adapter-utils@7.6.0': - resolution: {integrity: sha512-D8j3p0RnhLuufMaRLX6QqtGgPC5Ao3l5oFP6Q5AL0rTHi4vna+NzGEipwCsfvcSvaGFCbsH3lsTMbb4WvY+ovA==} + '@prisma/driver-adapter-utils@7.7.0': + resolution: {integrity: sha512-gZXREeu6mOk7zXfGFJgh86p7Vhj0sXNKp+4Cg1tWYo7V2dfncP2qxS2BiTmbIIha8xPqItkl0WSw38RuSq1HoQ==} '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': resolution: {integrity: sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==} - '@prisma/engines@7.6.0': - resolution: {integrity: sha512-Sn5edRzhHqgRV2M+A0eIbY442B4mReWWf3pKs/LKreYgW7oa/up8JtK/s4iv/EQA097cyboZ08mmkpbLp+tZ3w==} + '@prisma/engines@7.7.0': + resolution: {integrity: sha512-7fmcbT7HHXBq/b+3h/dO1JI3fd8l8q7erf7xP7pRprh58hmSSnG8mg9K3yjW3h9WaHWUwngVFpSxxxivaitQ2w==} '@prisma/extension-read-replicas@0.5.0': resolution: {integrity: sha512-t0kLjqFMte4wwGrZFhya4iFoyoOY4kjlyyE60WXZL66PqP6PcBpW/35eKb/3UcxgjJxcDlaJKfmGokFLOyafiQ==} peerDependencies: '@prisma/client': ^7.0.0 - '@prisma/fetch-engine@7.6.0': - resolution: {integrity: sha512-N575Ni95c3FkduWY/eKTHqNYgNbceZ1tQaSknVtJjpKmiiBXmniESn/GTxsDvICC4ZeiNrXxioGInzQrCdx16w==} + '@prisma/fetch-engine@7.7.0': + resolution: {integrity: sha512-TfyzveBQoK4xALzsTpVhB/0KG1N8zOK0ap+RnBMkzGUu3f98fnQ4QtXa2wlKPhsO2X8a3N5ugFQgcKNoHGmDfw==} '@prisma/get-platform@7.2.0': resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} - '@prisma/get-platform@7.6.0': - resolution: {integrity: sha512-ohZDwXvtmnbzOcutR2D13lDWpZP1wQjmPyztmt0AwXLzQI7q95EE7NYCvS+M6N6SivT+BM0NOqLmTH3wms4L3A==} + '@prisma/get-platform@7.7.0': + resolution: {integrity: sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==} '@prisma/query-plan-executor@7.2.0': resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} @@ -1682,54 +2109,27 @@ 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-spring/animated@10.0.3': - resolution: {integrity: sha512-7MrxADV3vaUADn2V9iYhaIL6iOWRx9nCJjYrsk2AHD2kwPr6fg7Pt0v+deX5RnCDmCKNnD6W5fasiyM8D+wzJQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@react-spring/animated@9.7.5': resolution: {integrity: sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/core@10.0.3': - resolution: {integrity: sha512-D4DwNO68oohDf/0HG2G0Uragzb9IA1oXblxrd6MZAcBcUQG2EHUWXewjdECMPLNmQvlYVyyBRH6gPxXM5DX7DQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@react-spring/core@9.7.5': resolution: {integrity: sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/rafz@10.0.3': - resolution: {integrity: sha512-Ri2/xqt8OnQ2iFKkxKMSF4Nqv0LSWnxXT4jXFzBDsHgeeH/cHxTLupAWUwmV9hAGgmEhBmh5aONtj3J6R/18wg==} - '@react-spring/rafz@9.7.5': resolution: {integrity: sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==} - '@react-spring/shared@10.0.3': - resolution: {integrity: sha512-geCal66nrkaQzUVhPkGomylo+Jpd5VPK8tPMEDevQEfNSWAQP15swHm+MCRG4wVQrQlTi9lOzKzpRoTL3CA84Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@react-spring/shared@9.7.5': resolution: {integrity: sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/types@10.0.3': - resolution: {integrity: sha512-H5Ixkd2OuSIgHtxuHLTt7aJYfhMXKXT/rK32HPD/kSrOB6q6ooeiWAXkBy7L8F3ZxdkBb9ini9zP9UwnEFzWgQ==} - '@react-spring/types@9.7.5': resolution: {integrity: sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==} - '@react-spring/web@10.0.3': - resolution: {integrity: sha512-ndU+kWY81rHsT7gTFtCJ6mrVhaJ6grFmgTnENipzmKqot4HGf5smPNK+cZZJqoGeDsj9ZsiWPW4geT/NyD484A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@react-spring/web@9.7.5': resolution: {integrity: sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==} peerDependencies: @@ -1754,47 +2154,54 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@redis/bloom@1.2.0': - resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} + '@redis/bloom@5.12.1': + resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==} + engines: {node: '>= 18.19.0'} peerDependencies: - '@redis/client': ^1.0.0 + '@redis/client': ^5.12.1 - '@redis/client@1.6.1': - resolution: {integrity: sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==} - engines: {node: '>=14'} - - '@redis/graph@1.1.1': - resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==} + '@redis/client@5.12.1': + resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==} + engines: {node: '>= 18.19.0'} peerDependencies: - '@redis/client': ^1.0.0 + '@node-rs/xxhash': ^1.1.0 + '@opentelemetry/api': '>=1 <2' + peerDependenciesMeta: + '@node-rs/xxhash': + optional: true + '@opentelemetry/api': + optional: true - '@redis/json@1.0.7': - resolution: {integrity: sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==} + '@redis/json@5.12.1': + resolution: {integrity: sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==} + engines: {node: '>= 18.19.0'} peerDependencies: - '@redis/client': ^1.0.0 + '@redis/client': ^5.12.1 - '@redis/search@1.2.0': - resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==} + '@redis/search@5.12.1': + resolution: {integrity: sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==} + engines: {node: '>= 18.19.0'} peerDependencies: - '@redis/client': ^1.0.0 + '@redis/client': ^5.12.1 - '@redis/time-series@1.1.0': - resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==} + '@redis/time-series@5.12.1': + resolution: {integrity: sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==} + engines: {node: '>= 18.19.0'} peerDependencies: - '@redis/client': ^1.0.0 + '@redis/client': ^5.12.1 - '@rollup/plugin-alias@5.1.1': - resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} - engines: {node: '>=14.0.0'} + '@rollup/plugin-alias@6.0.0': + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + rollup: '>=4.0.0' peerDependenciesMeta: rollup: optional: true - '@rollup/plugin-commonjs@25.0.8': - resolution: {integrity: sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==} - engines: {node: '>=14.0.0'} + '@rollup/plugin-commonjs@29.0.2': + resolution: {integrity: sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 peerDependenciesMeta: @@ -1810,8 +2217,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -1819,8 +2226,8 @@ packages: rollup: optional: true - '@rollup/plugin-replace@5.0.7': - resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==} + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -1828,9 +2235,9 @@ packages: rollup: optional: true - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} - engines: {node: '>=14.0.0'} + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} peerDependencies: rollup: ^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: @@ -1859,6 +2266,15 @@ packages: rollup: optional: true + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.60.1': resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} cpu: [arm] @@ -1990,9 +2406,6 @@ packages: '@schummar/icu-type-parser@1.21.5': resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==} - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@sinclair/typebox@0.34.40': resolution: {integrity: sha512-gwBNIP8ZAYev/ORDWW0QvxdwPXwxBtLsdsJgSc7eDIRt8ubP+rxUBzPsrwnu16fgEF8Bx4lh/+mvQvJzcTM6Kw==} @@ -2003,8 +2416,8 @@ packages: '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@sinonjs/fake-timers@15.3.2': + resolution: {integrity: sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -2094,68 +2507,80 @@ packages: peerDependencies: '@svgr/core': '*' - '@swc/core-darwin-arm64@1.15.11': - resolution: {integrity: sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==} + '@swc/core-darwin-arm64@1.15.26': + resolution: {integrity: sha512-OmcP96CFsNOwa65tamQayRcfqhNlcQ3YCWOq+0Wb+CAM4uB7kOMrXY41Gj4atthxrGhLQ9pg7Vk26iApb88idA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.15.11': - resolution: {integrity: sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==} + '@swc/core-darwin-x64@1.15.26': + resolution: {integrity: sha512-liTTTpKSv89ivIxcZ+iU1cRige9Y7JkOjVnJ2Ystzl+DsWNHqt7wLTTgm/u7gEqmmAS2JKryODLQn3q1UtFNPQ==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.15.11': - resolution: {integrity: sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==} + '@swc/core-linux-arm-gnueabihf@1.15.26': + resolution: {integrity: sha512-Y/g+m3I8CeBof5A3kWWOS6QA2HOIUytF5EeTgfwcAK+GKT/tGe7Xqo5svBtaqflU5od2zzbMTWqkinPXgRWGgA==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.15.11': - resolution: {integrity: sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==} + '@swc/core-linux-arm64-gnu@1.15.26': + resolution: {integrity: sha512-19IvwyPfBN/rz9s7qXhOTQmW0922+pjpRUUvIebu+CMM75nX6YuDzHsGx8hSmn5dS89SNaMCh1lgUuXqm++6jg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.15.11': - resolution: {integrity: sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==} + '@swc/core-linux-arm64-musl@1.15.26': + resolution: {integrity: sha512-iNlbvTIo425rkKzDLLWFJGnFXr3myETUdIDHcjuiPNZE8b0ogmcAuilC4yEJX7FSHGbnlsoJcCT2xf4b3VJmmQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.15.11': - resolution: {integrity: sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==} + '@swc/core-linux-ppc64-gnu@1.15.26': + resolution: {integrity: sha512-AuuEOtG+YXKIjIUup4RsxYNklx6XVB3WKWfhxG6hnfPrn7vp89RNOLbbyyprgj6Sk7k9ulwGVTJElEvmBNPSCA==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + + '@swc/core-linux-s390x-gnu@1.15.26': + resolution: {integrity: sha512-JcMDWQvW1BchUyRg8E0jHiTx7CQYpUr5uDEL1dnPDECrEjBEGG2ynmJ3XX70sWXql0JagqR1t3VpANYFWdUnqA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + + '@swc/core-linux-x64-gnu@1.15.26': + resolution: {integrity: sha512-FW7V7Mbpq4+PA7BiAq76LJs8MdNuUSylyuRVfQRkhIyeWadFroZ+KOPgjku8Z/fXzngxBRvsk+PGGB0t8mGcjA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.15.11': - resolution: {integrity: sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==} + '@swc/core-linux-x64-musl@1.15.26': + resolution: {integrity: sha512-w8erqMHsVcdGwUfJxF6LaiTuPoKnyLOcUbhLcxiXrlLt5MLjtlgcIeUY/NWK/oPoyqkgH+/i8pOJnMTxvl83ZQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.15.11': - resolution: {integrity: sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==} + '@swc/core-win32-arm64-msvc@1.15.26': + resolution: {integrity: sha512-uDCWCNpUiqkbvPmsuPUTn/P7ag9SqNXD2JT/W3dUu7yZ2krzN+nmmoQ2xRX63/J6RYiHI7aT4jo7Z++lsljlPA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.15.11': - resolution: {integrity: sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==} + '@swc/core-win32-ia32-msvc@1.15.26': + resolution: {integrity: sha512-2k1ax1QmmqLEnpC0uRCw7OXhBfyvdPqERBXupDasjYbChT6ZSO/uha28Bp38cw0viKIG79L27aTDkbkABsMW3w==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.15.11': - resolution: {integrity: sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==} + '@swc/core-win32-x64-msvc@1.15.26': + resolution: {integrity: sha512-aUuYecSEGa4SUSdyCWaI/vk8jdseifYnsF1GZQx2+piL8GIuT/5QrVcFfmes4Iwy7FIVXxtzD063z/FfpZ7K7w==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.15.11': - resolution: {integrity: sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==} + '@swc/core@1.15.26': + resolution: {integrity: sha512-tglZGyx8N5PC+x1Nd/JrZxqpqlcZoSuG9gTDKO6AuFToFiVB3uS8HvbKFuO7g3lJzvFf9riAb94xs9HU2UhAHQ==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -2175,14 +2600,14 @@ packages: '@swc/helpers@0.5.21': resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} - '@swc/types@0.1.25': - resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + '@swc/types@0.1.26': + resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} - '@tanstack/query-core@5.96.0': - resolution: {integrity: sha512-sfO3uQeol1BU7cRP6NYY7nAiX3GiNY20lI/dtSbKLwcIkYw/X+w/tEsQAkc544AfIhBX/IvH/QYtPHrPhyAKGw==} + '@tanstack/query-core@5.99.0': + resolution: {integrity: sha512-3Jv3WQG0BCcH7G+7lf/bP8QyBfJOXeY+T08Rin3GZ1bshvwlbPt7NrDHMEzGdKIOmOzvIQmxjk28YEQX60k7pQ==} - '@tanstack/react-query@5.96.0': - resolution: {integrity: sha512-6qbjdm1K5kizVKv9TNqhIN3doq2anRhdF2XaFMFSn4m8L22S69RV+FilvlyVT4RoJyMxtPU5rs4RpdFa/PEC7A==} + '@tanstack/react-query@5.99.0': + resolution: {integrity: sha512-OY2bCqPemT1LlqJ8Y2CUau4KELnIhhG9Ol3ZndPbdnB095pRbPo1cHuXTndg8iIwtoHTgwZjyaDnQ0xD0mYwAw==} peerDependencies: react: ^18 || ^19 @@ -2190,8 +2615,8 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@ts-morph/common@0.28.1': - resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==} + '@ts-morph/common@0.29.0': + resolution: {integrity: sha512-35oUmphHbJvQ/+UTwFNme/t2p3FoKiGJ5auTjjpNTop2dyREspirjMy82PLSC1pnDJ8ah1GU98hwpVt64YXQsg==} '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -2208,6 +2633,9 @@ packages: '@tsconfig/svelte@1.0.13': resolution: {integrity: sha512-5lYJP45Xllo4yE/RUBccBT32eBlRDbqN8r1/MIvQbKxW3aFqaYPCNgm8D5V20X4ShHcwvYWNlKg3liDh1MlBoA==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2232,9 +2660,6 @@ packages: '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -2254,8 +2679,8 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. - '@types/node@24.12.0': - resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/pg@8.20.0': resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} @@ -2274,12 +2699,15 @@ packages: '@types/sinonjs__fake-timers@8.1.1': resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} - '@types/sizzle@2.3.9': - resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} + '@types/sizzle@2.3.10': + resolution: {integrity: sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/tmp@0.2.6': + resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} + '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} @@ -2289,6 +2717,9 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -2299,6 +2730,104 @@ packages: react-aria-components: ^1.0.0 react-dom: ^18.0.0 || ^19.0.0 + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + '@xstate/fsm@1.6.5': resolution: {integrity: sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==} @@ -2311,6 +2840,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -2400,9 +2934,6 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2410,8 +2941,8 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - autoprefixer@10.4.21: - resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + autoprefixer@10.5.0: + resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -2431,19 +2962,19 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.8.0 + '@babel/core': ^7.11.0 || ^8.0.0-0 - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} babel-plugin-react-compiler@19.1.0-rc.2: resolution: {integrity: sha512-kSNA//p5fMO6ypG8EkEVPIqAjwIXm5tMjfD1XRPL/sRjYSbJ6UsvORfaeolNWnZ9n310aM0xJP7peW26BuCVzA==} @@ -2453,15 +2984,19 @@ packages: peerDependencies: '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-arraybuffer@1.0.2: resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} engines: {node: '>= 0.6.0'} @@ -2497,9 +3032,16 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -2509,6 +3051,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} engines: {node: '>= 6'} @@ -2612,10 +3159,6 @@ packages: chart.js: '>=2.8.0' date-fns: '>=2.0.0' - check-more-types@2.24.0: - resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} - engines: {node: '>= 0.8.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2624,22 +3167,22 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - ci-info@4.3.0: resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} engines: {node: '>=8'} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - citty@0.2.1: - resolution: {integrity: sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==} + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -2652,8 +3195,8 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + cli-table3@0.6.1: + resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==} engines: {node: 10.* || >= 12.*} cli-truncate@2.1.0: @@ -2682,8 +3225,8 @@ packages: code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} - collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -2707,6 +3250,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2775,11 +3322,6 @@ packages: typescript: optional: true - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -2796,10 +3338,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-blank-pseudo@3.0.3: - resolution: {integrity: sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==} - engines: {node: ^12 || ^14 || >=16} - hasBin: true + css-blank-pseudo@8.0.1: + resolution: {integrity: sha512-C5B2e5hCM4llrQkUms+KnWEMVW8K1n2XvX9G7ppfMZJQ7KAS/4rNnkP1Cs+HhWriOz1mWWTMFD4j1J7s31Dgug==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 @@ -2812,17 +3353,15 @@ packages: peerDependencies: postcss: ^8.0.9 - css-has-pseudo@3.0.4: - resolution: {integrity: sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==} - engines: {node: ^12 || ^14 || >=16} - hasBin: true + css-has-pseudo@8.0.0: + resolution: {integrity: sha512-Uz/bsHRbOeir/5Oeuz85tq/yLJLxX+3dpoRdjNTshs6jjqwUg8XaEZGDd0ci3fw7l53Srw0EkJ8mYan0eW5uGQ==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 - css-prefers-color-scheme@6.0.3: - resolution: {integrity: sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==} - engines: {node: ^12 || ^14 || >=16} - hasBin: true + css-prefers-color-scheme@11.0.0: + resolution: {integrity: sha512-fv0mgtwUhh2m9iio3Kxc2CkrogjIaRdMFaaqyzSFdii17JF4cfPyMNX72B15ZW2Nrr/NZUpxI4dec1VMHYJvdw==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 @@ -2848,8 +3387,8 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} - cssdb@7.11.2: - resolution: {integrity: sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A==} + cssdb@8.8.0: + resolution: {integrity: sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==} cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -2885,9 +3424,9 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - cypress@13.17.0: - resolution: {integrity: sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==} - engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} + cypress@15.14.0: + resolution: {integrity: sha512-AHt9YLKVl6uOFfXsLM3+LSZFwsx36BJRyFv4CjsqcRgr+V9kir0IPVRZUgqZVNudRalx771A1c4yR3DmXvSiBQ==} + engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0} hasBin: true d3-array@2.12.1: @@ -2949,17 +3488,16 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - date-fns-tz@1.3.8: - resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==} + date-fns-tz@3.2.0: + resolution: {integrity: sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==} peerDependencies: - date-fns: '>=2.0.0' + date-fns: ^3.0.0 || ^4.0.0 - date-fns@2.30.0: - resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} - engines: {node: '>=0.11'} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -2978,8 +3516,8 @@ packages: supports-color: optional: true - dedent@1.6.0: - resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -3002,12 +3540,8 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - - del@6.1.1: - resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} - engines: {node: '>=10'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} del@8.0.1: resolution: {integrity: sha512-gPqh0mKTPvaUZGAuHbrBUYKZWBNAeHG7TU3QH5EhVwPMyKvmfJaNXhcD2jTcXsJRRcffuho4vaYweu80dRrMGA==} @@ -3038,10 +3572,6 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -3088,8 +3618,8 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} dunder-proto@1.0.1: @@ -3111,6 +3641,9 @@ packages: electron-to-chromium@1.5.202: resolution: {integrity: sha512-NxbYjRmiHcHXV1Ws3fWUW+SLb62isauajk45LUJ/HgIOkUA7jLZu/X2Iif+X9FBNK8QkF9Zb4Q2mcwXCcY30mg==} + electron-to-chromium@1.5.340: + resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==} + emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} @@ -3170,8 +3703,13 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} engines: {node: '>=18'} hasBin: true @@ -3216,18 +3754,18 @@ packages: resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} engines: {node: '>=4'} - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - expect@30.1.1: resolution: {integrity: sha512-OKe7cdic4qbfWd/CcgwJvvCrNX2KWfuMZee9AfJHL1gTYmvqjBjZG1a2NwfhspBzxzlXwsN75WWpKTYfsJpBxg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -3311,16 +3849,30 @@ packages: forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + framer-motion@12.38.0: + resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} @@ -3354,10 +3906,6 @@ packages: generic-names@4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} - generic-pool@3.9.0: - resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} - engines: {node: '>= 4'} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -3396,9 +3944,6 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} - getos@3.2.1: - resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} - getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -3436,10 +3981,6 @@ packages: resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} engines: {node: '>=8'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - globby@14.1.0: resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} @@ -3457,8 +3998,8 @@ packages: graphmatch@1.1.1: resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} engines: {node: '>=0.4.7'} hasBin: true @@ -3489,10 +4030,18 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + hono@4.12.9: resolution: {integrity: sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==} engines: {node: '>=16.9.0'} @@ -3531,8 +4080,8 @@ packages: peerDependencies: postcss: ^8.1.0 - icu-minify@4.8.4: - resolution: {integrity: sha512-lRfPX67iofadgfhMvjs37GqLB8ErDaNERte2XNpm69bP10D6RFV/tAWYX0lEBwsdLWxpliKVh2TT4NEa63yuWw==} + icu-minify@4.9.1: + resolution: {integrity: sha512-6NkfF9GHHFouqnz+wuiLjCWQiyxoEyJ5liUv4Jxxo/8wyhV7MY0L0iTEGDAVEa4aAD58WqTxFMa20S5nyMjwNw==} ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -3594,8 +4143,8 @@ packages: internmap@1.0.1: resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} - intl-messageformat@11.2.0: - resolution: {integrity: sha512-IhghAA8n4KSlXuWKzYsWyWb82JoYTzShfyvdSF85oJPnNOjvv4kAo7S7Jtkm3/vJ53C7dQNRO+Gpnj3iWgTjBQ==} + intl-messageformat@11.2.1: + resolution: {integrity: sha512-1gAVEUt3wEPvTqML4Fsw9klZV5j0vszQxayP/fi6gUroAc8AUHiNaisBKLWxybL1AdWq1mP07YV1q8v4N92ilQ==} ipaddr.js@2.3.0: resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} @@ -3624,8 +4173,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + is-ci@4.1.0: + resolution: {integrity: sha512-Ab9bQDQ11lWootZUI5qxgN2ZXwxNI5hTwnsvOc1wyxQ7zQ8OkEDw79mI0+9jI3x432NfwbVRru+3noJfXF6lSQ==} hasBin: true is-core-module@2.16.1: @@ -3640,9 +4189,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-docker@4.0.0: + resolution: {integrity: sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==} + engines: {node: '>=20'} hasBin: true is-extglob@2.1.1: @@ -3673,9 +4222,9 @@ packages: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} engines: {node: '>=10'} - is-localhost-ip@2.0.0: - resolution: {integrity: sha512-vlgs2cSgMOfnKU8c1ewgKPyum9rVrjjLLW2HBdL5i0iAJjOs8NY55ZBd/hqUTaYR0EO9CKZd3hVSC2HlIbygTQ==} - engines: {node: '>=12'} + is-localhost-ip@3.0.1: + resolution: {integrity: sha512-OwNA8bw72L/gDVfCrhJ3GFb3AGp+I7t+cvJaQGkiLZgeBAZmAygIduAdhLq56JycuJ68NCICxA2yyIaAtbR9Kg==} + engines: {node: '>=18'} is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} @@ -3696,10 +4245,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-cwd@2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} - is-path-cwd@3.0.0: resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3778,8 +4323,8 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isbot@5.1.37: - resolution: {integrity: sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ==} + isbot@5.1.39: + resolution: {integrity: sha512-obH0yYahGXdzNxo+djmHhBYThUKDkz565cxkIlt2L9hXfv1NlaLKoDBHo6KxXsYrIXx2RK3x5vY36CfZcobxEw==} engines: {node: '>=18'} isexe@2.0.0: @@ -3792,10 +4337,6 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - istanbul-lib-instrument@6.0.3: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} @@ -3804,28 +4345,28 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-cli@30.3.0: + resolution: {integrity: sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -3833,74 +4374,73 @@ packages: node-notifier: optional: true - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' + esbuild-register: '>=3.4.0' ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': optional: true + esbuild-register: + optional: true ts-node: optional: true - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-diff@30.1.1: resolution: {integrity: sha512-LUU2Gx8EhYxpdzTR6BmjL1ifgOAQJQELTHOiPv9KITaKjZvJ9Jmgigx01tuZ49id37LorpGc9dPBPlXTboXScw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-matcher-utils@30.1.1: resolution: {integrity: sha512-SuH2QVemK48BNTqReti6FtjsMPFsSOD/ZzRxU1TttR7RiRsRSe78d03bb4Cx6D4bQC/80Q8U4VnaaAH9FlbZ9w==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-message-util@30.1.0: resolution: {integrity: sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-mock@30.0.5: resolution: {integrity: sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-pnp-resolver@1.2.3: resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} @@ -3910,57 +4450,53 @@ packages: jest-resolve: optional: true - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-regex-util@30.0.1: resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-util@30.0.5: resolution: {integrity: sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.3.0: + resolution: {integrity: sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -3979,8 +4515,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true js-yaml@4.1.0: @@ -4046,10 +4582,6 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - lazy-ass@1.6.0: - resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} - engines: {node: '> 0.8'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -4123,8 +4655,8 @@ packages: lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -4159,14 +4691,11 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@1.7.0: - resolution: {integrity: sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg==} + lucide-react@1.8.0: + resolution: {integrity: sha512-WuvlsjngSk7TnTBJ1hsCy3ql9V9VOdcPkd3PKcSmM34vJD8KG6molxz7m7zbYFgICwsanQWmJ13JlYs4Zp7Arw==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -4184,8 +4713,8 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - maxmind@5.0.5: - resolution: {integrity: sha512-1lcH2kMjbBpCFhuHaMU32vz8CuOsKttRcWMQyXvtlklopCzN7NNHSVR/h9RYa8JPuFTGmkn2vYARm+7cIGuqDw==} + maxmind@5.0.6: + resolution: {integrity: sha512-5bvd/u+kIaTqaGM+xkXjatzQw1dQfSmlLggr2W1EKMyMxSgx2woZyusLpNpZ4DdPmL+1bbJWeo4LXsi6bC0Iew==} engines: {node: '>=12', npm: '>=6'} mdn-data@2.0.14: @@ -4197,12 +4726,6 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - memoize-one@5.2.1: - resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - - memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -4230,13 +4753,16 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} - engines: {node: 20 || >=22} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} @@ -4266,6 +4792,26 @@ packages: resolution: {integrity: sha512-7e87vk0DdWT647wjcfEtWeMtjm+zVGqNohN/aeIymbUfjHQ2T4Sx5kM+1irVDBSloNC3CkGKxswdMoo8yhqTDg==} engines: {node: '>=10', npm: '>=6'} + motion-dom@12.38.0: + resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==} + + motion-utils@12.36.0: + resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} + + motion@12.38.0: + resolution: {integrity: sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4285,6 +4831,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4295,15 +4846,15 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next-intl-swc-plugin-extractor@4.8.4: - resolution: {integrity: sha512-iA9/jaDfFTQYypnbLP7UGO0x3z2uuvHdNgIOtl53EwlVvQpp1MW77qKF+v87uYBoAwyniwGEhNXsO6qWEI+EzA==} + next-intl-swc-plugin-extractor@4.9.1: + resolution: {integrity: sha512-8whJJ6oxJz8JqkHarggmmuEDyXgC7nEnaPhZD91CJwEWW4xp0AST3Mw17YxvHyP2vAF3taWfFbs1maD+WWtz3w==} - next-intl@4.8.3: - resolution: {integrity: sha512-PvdBDWg+Leh7BR7GJUQbCDVVaBRn37GwDBWc9sv0rVQOJDQ5JU1rVzx9EEGuOGYo0DHAl70++9LQ7HxTawdL7w==} + next-intl@4.9.1: + resolution: {integrity: sha512-N7ga0CjtYcdxNvaKNIi6eJ2mmatlHK5hp8rt0YO2Omoc1m0gean242/Ukdj6+gJNiReBVcYIjK0HZeNx7CV1ug==} peerDependencies: next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 - typescript: ^5.0.0 + typescript: '*' peerDependenciesMeta: typescript: optional: true @@ -4356,6 +4907,13 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} + + non-error@0.1.0: + resolution: {integrity: sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==} + engines: {node: '>=20'} + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -4363,10 +4921,6 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} @@ -4565,14 +5119,18 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pidtree@0.3.1: resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} engines: {node: '>=0.10'} @@ -4611,11 +5169,11 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss-attribute-case-insensitive@5.0.2: - resolution: {integrity: sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==} - engines: {node: ^12 || ^14 || >=16} + postcss-attribute-case-insensitive@8.0.0: + resolution: {integrity: sha512-fovIPEV35c2JzVXdmP+sp2xirbBMt54J+upU8u6TSj410kUU5+axgEzvBBSAX8KCybze8CFCelzFAw/FfWg2TA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-calc@8.2.4: resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} @@ -4628,23 +5186,23 @@ packages: peerDependencies: postcss: ^8.4.6 - postcss-color-functional-notation@4.2.4: - resolution: {integrity: sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==} - engines: {node: ^12 || ^14 || >=16} - peerDependencies: - postcss: ^8.2 - - postcss-color-hex-alpha@8.0.4: - resolution: {integrity: sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==} - engines: {node: ^12 || ^14 || >=16} + postcss-color-functional-notation@8.0.3: + resolution: {integrity: sha512-MyaFK+3PusD7F2+qlMDP6+zfSgHWP17AtmvHQs44W3+Qbb39VptVDVRJ4Lf7gHSVffW5ekEy/XrsZ0S0t34hrA==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 - postcss-color-rebeccapurple@7.1.1: - resolution: {integrity: sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==} - engines: {node: ^12 || ^14 || >=16} + postcss-color-hex-alpha@11.0.0: + resolution: {integrity: sha512-NCGa6vjIyrjosz9GqRxVKbONBklz5TeipYqTJp3IqbnBWlBq5e5EMtG6MaX4vqk9LzocPfMQkuRK9tfk+OQuKg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 + + postcss-color-rebeccapurple@11.0.0: + resolution: {integrity: sha512-g9561mx7cbdqx7XeO/L+lJzVlzu7bICyXr72efBVKZGxIhvBBJf9fGXn3Cb6U4Bwh3LbzQO2e9NWBLVYdX5Eag==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss: ^8.4 postcss-colormin@5.3.1: resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} @@ -4658,29 +5216,29 @@ packages: peerDependencies: postcss: ^8.2.15 - postcss-custom-media@8.0.2: - resolution: {integrity: sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==} - engines: {node: ^12 || ^14 || >=16} + postcss-custom-media@12.0.1: + resolution: {integrity: sha512-66syE14+VeqkUf0rRX0bvbTCbNRJF132jD+ceo8th1dap2YJEAqpdh5uG98CE3IbgHT7m9XM0GIlOazNWqQdeA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.3 + postcss: ^8.4 - postcss-custom-properties@12.1.11: - resolution: {integrity: sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==} - engines: {node: ^12 || ^14 || >=16} + postcss-custom-properties@15.0.1: + resolution: {integrity: sha512-cuyq8sd8dLY0GLbelz1KB8IMIoDECo6RVXMeHeXY2Uw3Q05k/d1GVITdaKLsheqrHbnxlwxzSRZQQ5u+rNtbMg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - postcss-custom-selectors@6.0.3: - resolution: {integrity: sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==} - engines: {node: ^12 || ^14 || >=16} + postcss-custom-selectors@9.0.1: + resolution: {integrity: sha512-2XBELy4DmdVKimChfaZ2id9u9CSGYQhiJ53SvlfBvMTzLMW2VxuMb9rHsMSQw9kRq/zSbhT5x13EaK8JSmK8KQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.3 + postcss: ^8.4 - postcss-dir-pseudo-class@6.0.5: - resolution: {integrity: sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==} - engines: {node: ^12 || ^14 || >=16} + postcss-dir-pseudo-class@10.0.0: + resolution: {integrity: sha512-DmtIzULpyC8XaH4b5AaUgt4Jic4QmrECqidNCdR7u7naQFdnxX80YI06u238a+ZVRXwURDxVzy0s/UQnWmpVeg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-discard-comments@5.1.2: resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} @@ -4706,15 +5264,9 @@ packages: peerDependencies: postcss: ^8.2.15 - postcss-double-position-gradients@3.1.2: - resolution: {integrity: sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==} - engines: {node: ^12 || ^14 || >=16} - peerDependencies: - postcss: ^8.2 - - postcss-env-function@4.0.6: - resolution: {integrity: sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==} - engines: {node: ^12 || ^14 || >=16} + postcss-double-position-gradients@7.0.0: + resolution: {integrity: sha512-Msr/dxj8Os7KLJE5Hdhvprwm3K5Zrh1KTY0eFN3ngPKNkej/Usy4BM9JQmqE6CLAkDpHoQVsi4snbL72CPt6qg==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 @@ -4723,15 +5275,15 @@ packages: peerDependencies: postcss: ^8.1.4 - postcss-focus-visible@6.0.4: - resolution: {integrity: sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==} - engines: {node: ^12 || ^14 || >=16} + postcss-focus-visible@11.0.0: + resolution: {integrity: sha512-VG1a9kBKizUBWS66t5xyB4uLONBnvZLCmZXxT40FALu8EF0QgVZBYy5ApC0KhmpHsv+pvHMJHB3agKHwmocWjw==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 - postcss-focus-within@5.0.4: - resolution: {integrity: sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==} - engines: {node: ^12 || ^14 || >=16} + postcss-focus-within@10.0.0: + resolution: {integrity: sha512-dvql0fzUTG+gcJYp+KTbag5vAjuo94LDYZHkqDV1rnf5gPGer1v/SrmIZBdvKU8moep3HbcbujqGjzSb3DL53Q==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 @@ -4740,34 +5292,29 @@ packages: peerDependencies: postcss: ^8.1.0 - postcss-gap-properties@3.0.5: - resolution: {integrity: sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==} - engines: {node: ^12 || ^14 || >=16} + postcss-gap-properties@7.0.0: + resolution: {integrity: sha512-PSDF2QoZMRUbsINvXObQgxx4HExRP85QTT8qS/YN9fBsCPWCqUuwqAD6E6PNp0BqL/jU1eyWUBORaOK/J/9LDA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - postcss-image-set-function@4.0.7: - resolution: {integrity: sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==} - engines: {node: ^12 || ^14 || >=16} + postcss-image-set-function@8.0.0: + resolution: {integrity: sha512-rEGNkOkNusf4+IuMmfEoIdLuVmvbExGbmG+MIsyV6jR5UaWSoyPcAYHV/PxzVDCmudyF+2Nh/o6Ub2saqUdnuA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} + postcss-import@16.1.1: + resolution: {integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==} + engines: {node: '>=18.0.0'} peerDependencies: postcss: ^8.0.0 - postcss-initial@4.0.1: - resolution: {integrity: sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==} + postcss-lab-function@8.0.3: + resolution: {integrity: sha512-rUa27RLVXjMn1aDkHEt5dRsK80+bAACPr8w5Ow0BkIlfH6gEk0Mh1I0REkYhtp4UhKFw1HLEk3AzvKBi6BGOqw==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.0.0 - - postcss-lab-function@4.2.1: - resolution: {integrity: sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==} - engines: {node: ^12 || ^14 || >=16} - peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -4799,18 +5346,12 @@ packages: yaml: optional: true - postcss-logical@5.0.4: - resolution: {integrity: sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==} - engines: {node: ^12 || ^14 || >=16} + postcss-logical@9.0.0: + resolution: {integrity: sha512-A4LNd9dk3q/juEUA9Gd8ALhBO3TeOeYurnyHLlf2aAToD94VHR8c5Uv7KNmf8YVRhTxvWsyug4c5fKtARzyIRQ==} + engines: {node: '>=20.19.0'} peerDependencies: postcss: ^8.4 - postcss-media-minmax@5.0.0: - resolution: {integrity: sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - postcss: ^8.1.0 - postcss-merge-longhand@5.1.7: resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -4876,11 +5417,11 @@ packages: peerDependencies: postcss: ^8.0.0 - postcss-nesting@10.2.0: - resolution: {integrity: sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==} - engines: {node: ^12 || ^14 || >=16} + postcss-nesting@14.0.0: + resolution: {integrity: sha512-YGFOfVrjxYfeGTS5XctP1WCI5hu8Lr9SmntjfRC+iX5hCihEO+QZl9Ra+pkjqkgoVdDKvb2JccpElcowhZtzpw==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-normalize-charset@5.1.0: resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} @@ -4936,11 +5477,11 @@ packages: peerDependencies: postcss: ^8.2.15 - postcss-opacity-percentage@1.1.3: - resolution: {integrity: sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==} - engines: {node: ^12 || ^14 || >=16} + postcss-opacity-percentage@3.0.0: + resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==} + engines: {node: '>=18'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-ordered-values@5.1.3: resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} @@ -4948,34 +5489,34 @@ packages: peerDependencies: postcss: ^8.2.15 - postcss-overflow-shorthand@3.0.4: - resolution: {integrity: sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==} - engines: {node: ^12 || ^14 || >=16} + postcss-overflow-shorthand@7.0.0: + resolution: {integrity: sha512-9SLpjoUdGRoRrzoOdX66HbUs0+uDwfIAiXsRa7piKGOqPd6F4ZlON9oaDSP5r1Qpgmzw5L9Ht0undIK6igJPMA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-page-break@3.0.4: resolution: {integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==} peerDependencies: postcss: ^8 - postcss-place@7.0.5: - resolution: {integrity: sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==} - engines: {node: ^12 || ^14 || >=16} + postcss-place@11.0.0: + resolution: {integrity: sha512-fAifpyjQ+fuDRp2nmF95WbotqbpjdazebedahXdfBxy5sHembOLpBQ1cHveZD9ZmjK26tYM8tikeNaUlp/KfHA==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - postcss-preset-env@7.8.3: - resolution: {integrity: sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==} - engines: {node: ^12 || ^14 || >=16} + postcss-preset-env@11.2.1: + resolution: {integrity: sha512-dqL7WR5wg9yP/+6pTHIsIeIpK6XVghJDE4/r4ZSdr5ExrbLiN5x78gly0Xs0MLGbHy2oT3WWNfbxowmnw9BurQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 - postcss-pseudo-class-any-link@7.1.6: - resolution: {integrity: sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==} - engines: {node: ^12 || ^14 || >=16} + postcss-pseudo-class-any-link@11.0.0: + resolution: {integrity: sha512-DNFZ4GMa3C3pU5dM+UCTG1CEeLtS1ZqV5DKSqCTJQMn1G5jnd/30fS8+A7H4o5bSD3MOcnx+VgI+xPE9Z5Wvig==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-reduce-initial@5.1.2: resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} @@ -4994,11 +5535,11 @@ packages: peerDependencies: postcss: ^8.0.3 - postcss-selector-not@6.0.1: - resolution: {integrity: sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==} - engines: {node: ^12 || ^14 || >=16} + postcss-selector-not@9.0.0: + resolution: {integrity: sha512-xhAtTdHnVU2M/CrpYOPyRUvg3njhVlKmn2GNYXDaRJV9Ygx4d5OkSkc7NINzjUqnbDFtaKXlISOBeyMXU/zyFQ==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.2 + postcss: ^8.4 postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} @@ -5008,6 +5549,10 @@ packages: resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} engines: {node: '>=4'} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss-svgo@5.1.0: resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} engines: {node: ^10 || ^12 || >=14.0} @@ -5027,8 +5572,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -5068,16 +5613,16 @@ packages: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} engines: {node: '>=6'} - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pretty-format@30.0.5: resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - prisma@7.6.0: - resolution: {integrity: sha512-OKJIPT81K3+F+AayIkY/Y3mkF2NWoFh7lZApaaqPYy7EHILKdO0VsmGkP+hDKYTySHsFSyLWXm/JgcR1B8fY1Q==} + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + prisma@7.7.0: + resolution: {integrity: sha512-HlgwRBt1uEFB9LStHL4HLYDvoi4BNu1rYA0hPG0zCAEyK9SaZBqp7E5Rjpc3Qh8Lex/ye/svoHZ0OWoFNhWxuQ==} engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true peerDependencies: @@ -5113,8 +5658,8 @@ packages: proxy-from-env@1.0.0: resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} @@ -5122,8 +5667,11 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + pure-rand@8.4.0: + resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} + + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -5132,9 +5680,6 @@ packages: raf-schd@4.0.3: resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} @@ -5155,10 +5700,10 @@ packages: peerDependencies: react: ^19.2.5 - react-error-boundary@4.1.2: - resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + react-error-boundary@6.1.1: + resolution: {integrity: sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==} peerDependencies: - react: '>=16.13.1' + react: ^18.0.0 || ^19.0.0 react-hook-form@7.71.1: resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} @@ -5184,18 +5729,18 @@ packages: redux: optional: true - react-resizable-panels@4.8.0: - resolution: {integrity: sha512-2uEABkewb3ky/ZgIlAUxWa1W/LjsK494fdV1QsXxst7CDRHCzo7h22tWWu3NNaBjmiuriOCt3CvhipnaYcpoIw==} + react-resizable-panels@4.10.0: + resolution: {integrity: sha512-frjewRQt7TCv/vCH1pJfjZ7RxAhr5pKuqVQtVgzFq/vherxBFOWyC3xMbryx5Ti2wylViGUFc93Etg4rB3E0UA==} 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==} + react-simple-maps@3.0.0: + resolution: {integrity: sha512-vKNFrvpPG8Vyfdjnz5Ne1N56rZlDfHXv5THNXOVZMqbX1rWZA48zQuYT03mx6PAKanqarJu/PDLgshIZAfHHqw==} peerDependencies: prop-types: ^15.7.2 - react: ^16.8.0 || 17.x - react-dom: ^16.8.0 || 17.x + react: ^16.8.0 || 17.x || 18.x + react-dom: ^16.8.0 || 17.x || 18.x react-stately@3.46.0: resolution: {integrity: sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==} @@ -5211,12 +5756,11 @@ packages: react-dom: optional: true - react-window@1.8.11: - resolution: {integrity: sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==} - engines: {node: '>8.0.0'} + react-window@2.2.7: + resolution: {integrity: sha512-SH5nvfUQwGHYyriDUAOt7wfPsfG9Qxd6OdzQxl5oQ4dsSsUicqQvjV7dR+NqZ4coY0fUn3w1jnC5PwzIUWEg5w==} peerDependencies: - 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: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 react@19.2.5: resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} @@ -5236,8 +5780,9 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - redis@4.7.1: - resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==} + redis@5.12.1: + resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} + engines: {node: '>= 18.19.0'} redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} @@ -5282,15 +5827,16 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} hasBin: true + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -5306,11 +5852,6 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rollup-plugin-copy@3.5.0: resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} engines: {node: '>=8.3'} @@ -5328,11 +5869,17 @@ packages: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 || ^6.0 - rollup-plugin-node-externals@8.1.2: - resolution: {integrity: sha512-EuB6/lolkMLK16gvibUjikERq5fCRVIGwD2xue/CrM8D0pz5GXD2V6N8IrgxegwbcUoKkUFI8VYCEEv8MMvgpA==} - engines: {node: '>= 21 || ^20.6.0 || ^18.19.0'} + rollup-plugin-node-externals@9.0.1: + resolution: {integrity: sha512-Yp91CX1ebDA8s4+BY7bOOdhF8VRR1XAKnSsHeVhYg4DW4MRXPsF4F2FnSsN9ghJgFhHl3L1uyK7A9NA/SF4Zgw==} + engines: {node: '>= 24'} peerDependencies: rollup: ^4.0.0 + vite: '>=5.0.0' + peerDependenciesMeta: + rollup: + optional: true + vite: + optional: true rollup-plugin-peer-deps-external@2.2.4: resolution: {integrity: sha512-AWdukIM1+k5JDdAqV/Cxd+nejvno2FVLVeZ74NKggm3Q5s9cbbcOgUPGdbxPi4BXu7xGaZ8HG12F+thImYu/0g==} @@ -5414,12 +5961,13 @@ packages: 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'} + serialize-error@13.0.1: + resolution: {integrity: sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==} + engines: {node: '>=20'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.5: + resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + engines: {node: '>=20.0.0'} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -5502,8 +6050,9 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + smob@1.6.1: + resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} + engines: {node: '>=20.0.0'} snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -5607,8 +6156,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -5683,6 +6232,20 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + systeminformation@5.31.5: + resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} + engines: {node: '>=8.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} @@ -5703,8 +6266,8 @@ packages: resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} engines: {node: '>=18'} - terser@5.43.1: - resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} hasBin: true @@ -5712,8 +6275,8 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} - thenby@1.3.4: - resolution: {integrity: sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==} + thenby@1.4.0: + resolution: {integrity: sha512-D+BkEl5MpeTbQ1Rz0io/TLZmwmYUAgvUpS1r2eKUvPicYOnpqzjZE6bVa7rSEYv189zkSM+CVc+hG5X7nVe9LQ==} thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -5731,21 +6294,25 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tiny-lru@11.4.7: - resolution: {integrity: sha512-w/Te7uMUVeH0CR8vZIjr+XiN41V+30lkDdK+NRIDCUYKKuL9VcmaUEmaPISuwGhLlrTGh5yu18lENtR9axSxYw==} - engines: {node: '>=12'} + tiny-lru@13.0.0: + resolution: {integrity: sha512-xDHxKKS1FdF0Tv2P+QT7IeSEg74K/8cEDzbv3Tv6UyHHUgBOjOiQiBp818MGj66dhurQus/IBcoAbwIKtSGc6Q==} + engines: {node: '>=14'} tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.4: - resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} engines: {node: '>=18'} tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} @@ -5779,8 +6346,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-jest@29.4.6: - resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} + ts-jest@29.4.9: + resolution: {integrity: sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -5791,7 +6358,7 @@ packages: esbuild: '*' jest: ^29.0.0 || ^30.0.0 jest-util: ^29.0.0 || ^30.0.0 - typescript: '>=4.3 <6' + typescript: '>=4.3 <7' peerDependenciesMeta: '@babel/core': optional: true @@ -5806,8 +6373,8 @@ packages: jest-util: optional: true - ts-morph@27.0.2: - resolution: {integrity: sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==} + ts-morph@28.0.0: + resolution: {integrity: sha512-Wp3tnZ2bzwxyTZMtgWVzXDfm7lB1Drz+y9DmmYH/L702PQhPyVrp3pkou3yIz4qjS14GY9kcpmLiOOMvl8oG1g==} ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -5823,6 +6390,9 @@ packages: '@swc/wasm': optional: true + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -5864,10 +6434,18 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-fest@5.6.0: + resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} + engines: {node: '>=20'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -5884,8 +6462,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -5908,8 +6486,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} @@ -5923,6 +6501,9 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} @@ -5933,21 +6514,17 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - use-intl@4.8.4: - resolution: {integrity: sha512-H4Hs0LdyKowskCHRuPajOPx4X+UZZije4GPgIcX9N+U87Y4z4Vpfl7sp9OmhJvCUoTr3HOeUiNvjiqEKBYlsCw==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-intl@4.9.1: + resolution: {integrity: sha512-iGVV/xFYlhe3btafRlL8RPLD2Jsuet4yqn9DR6LWWbMhULsJnXgLonDkzDmsAIBIwFtk02oJuX/Ox2vwHKF+UQ==} peerDependencies: react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 - use-memo-one@1.1.3: - resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -6040,9 +6617,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} @@ -6055,9 +6632,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - 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'} @@ -6135,6 +6709,8 @@ snapshots: '@babel/compat-data@7.28.0': {} + '@babel/compat-data@7.29.0': {} + '@babel/core@7.28.3': dependencies: '@ampproject/remapping': 2.3.0 @@ -6155,6 +6731,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/generator@7.28.3': dependencies: '@babel/parser': 7.28.3 @@ -6163,6 +6759,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.28.0 @@ -6171,6 +6775,14 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + '@babel/helper-globals@7.28.0': {} '@babel/helper-module-imports@7.27.1': @@ -6180,6 +6792,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 @@ -6189,7 +6808,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} '@babel/helper-string-parser@7.27.1': {} @@ -6204,96 +6832,105 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.28.2 + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@babel/parser@7.28.3': dependencies: '@babel/types': 7.28.2 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.3)': + '@babel/parser@7.29.2': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.29.0 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.3)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.3)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.3)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.3)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.3)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.3)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.3)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.3)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/runtime@7.28.3': {} + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/runtime@7.29.2': {} '@babel/template@7.27.2': dependencies: @@ -6301,6 +6938,12 @@ snapshots: '@babel/parser': 7.28.3 '@babel/types': 7.28.2 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@babel/traverse@7.28.3': dependencies: '@babel/code-frame': 7.27.1 @@ -6313,46 +6956,63 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.2': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@0.2.3': {} - '@biomejs/biome@2.4.10': + '@biomejs/biome@2.4.12': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.10 - '@biomejs/cli-darwin-x64': 2.4.10 - '@biomejs/cli-linux-arm64': 2.4.10 - '@biomejs/cli-linux-arm64-musl': 2.4.10 - '@biomejs/cli-linux-x64': 2.4.10 - '@biomejs/cli-linux-x64-musl': 2.4.10 - '@biomejs/cli-win32-arm64': 2.4.10 - '@biomejs/cli-win32-x64': 2.4.10 + '@biomejs/cli-darwin-arm64': 2.4.12 + '@biomejs/cli-darwin-x64': 2.4.12 + '@biomejs/cli-linux-arm64': 2.4.12 + '@biomejs/cli-linux-arm64-musl': 2.4.12 + '@biomejs/cli-linux-x64': 2.4.12 + '@biomejs/cli-linux-x64-musl': 2.4.12 + '@biomejs/cli-win32-arm64': 2.4.12 + '@biomejs/cli-win32-x64': 2.4.12 - '@biomejs/cli-darwin-arm64@2.4.10': + '@biomejs/cli-darwin-arm64@2.4.12': optional: true - '@biomejs/cli-darwin-x64@2.4.10': + '@biomejs/cli-darwin-x64@2.4.12': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.10': + '@biomejs/cli-linux-arm64-musl@2.4.12': optional: true - '@biomejs/cli-linux-arm64@2.4.10': + '@biomejs/cli-linux-arm64@2.4.12': optional: true - '@biomejs/cli-linux-x64-musl@2.4.10': + '@biomejs/cli-linux-x64-musl@2.4.12': optional: true - '@biomejs/cli-linux-x64@2.4.10': + '@biomejs/cli-linux-x64@2.4.12': optional: true - '@biomejs/cli-win32-arm64@2.4.10': + '@biomejs/cli-win32-arm64@2.4.12': optional: true - '@biomejs/cli-win32-x64@2.4.10': + '@biomejs/cli-win32-x64@2.4.12': optional: true '@clack/core@0.5.0': @@ -6372,92 +7032,331 @@ snapshots: dependencies: '@clickhouse/client-common': 1.18.2 - '@colors/colors@1.5.0': - optional: true - '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@csstools/postcss-cascade-layers@1.1.1(postcss@8.5.8)': + '@csstools/cascade-layer-name-parser@3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.2) - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 - '@csstools/postcss-color-function@1.1.1(postcss@8.5.8)': + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - postcss: 8.5.8 + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-tokenizer@4.0.0': {} + + '@csstools/media-query-list-parser@5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/postcss-alpha-function@2.0.4(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-cascade-layers@6.0.0(postcss@8.5.10)': + dependencies: + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-color-function-display-p3-linear@2.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-color-function@5.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-color-mix-function@4.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-color-mix-variadic-function-arguments@2.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-content-alt-text@3.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-contrast-color-function@3.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-exponential-functions@3.0.2(postcss@8.5.10)': + dependencies: + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-font-format-keywords@5.0.0(postcss@8.5.10)': + dependencies: + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-font-format-keywords@1.0.1(postcss@8.5.8)': + '@csstools/postcss-font-width-property@1.0.0(postcss@8.5.10)': dependencies: - postcss: 8.5.8 + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-gamut-mapping@3.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-gradients-interpolation-method@6.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-hwb-function@5.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-ic-unit@5.0.0(postcss@8.5.10)': + dependencies: + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-hwb-function@1.0.2(postcss@8.5.8)': + '@csstools/postcss-initial@3.0.0(postcss@8.5.10)': dependencies: - postcss: 8.5.8 + postcss: 8.5.10 + + '@csstools/postcss-is-pseudo-class@6.0.0(postcss@8.5.10)': + dependencies: + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-light-dark-function@3.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-logical-float-and-clear@4.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 + + '@csstools/postcss-logical-overflow@3.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 + + '@csstools/postcss-logical-overscroll-behavior@3.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 + + '@csstools/postcss-logical-resize@4.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-ic-unit@1.0.1(postcss@8.5.8)': + '@csstools/postcss-logical-viewport-units@4.0.0(postcss@8.5.10)': dependencies: - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - postcss: 8.5.8 + '@csstools/css-tokenizer': 4.0.0 + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-media-minmax@3.0.2(postcss@8.5.10)': + dependencies: + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/media-query-list-parser': 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.10 + + '@csstools/postcss-media-queries-aspect-ratio-number-values@4.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/media-query-list-parser': 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.10 + + '@csstools/postcss-mixins@1.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-nested-calc@5.0.0(postcss@8.5.10)': + dependencies: + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-is-pseudo-class@2.0.7(postcss@8.5.8)': + '@csstools/postcss-normalize-display-values@5.0.1(postcss@8.5.10)': dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.2) - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 - - '@csstools/postcss-nested-calc@1.0.0(postcss@8.5.8)': - dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-normalize-display-values@1.0.1(postcss@8.5.8)': + '@csstools/postcss-oklab-function@5.0.3(postcss@8.5.10)': dependencies: - postcss: 8.5.8 + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-position-area-property@2.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 + + '@csstools/postcss-progressive-custom-properties@5.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-oklab-function@1.1.1(postcss@8.5.8)': + '@csstools/postcss-property-rule-prelude-list@2.0.0(postcss@8.5.10)': dependencies: - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - postcss: 8.5.8 + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-random-function@3.0.2(postcss@8.5.10)': + dependencies: + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-relative-color-syntax@4.0.3(postcss@8.5.10)': + dependencies: + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + '@csstools/postcss-scope-pseudo-class@5.0.0(postcss@8.5.10)': + dependencies: + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-sign-functions@2.0.2(postcss@8.5.10)': + dependencies: + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-stepped-value-functions@5.0.2(postcss@8.5.10)': + dependencies: + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-syntax-descriptor-syntax-production@2.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-system-ui-font-family@2.0.0(postcss@8.5.10)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + + '@csstools/postcss-text-decoration-shorthand@5.0.3(postcss@8.5.10)': + dependencies: + '@csstools/color-helpers': 6.0.2 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - '@csstools/postcss-progressive-custom-properties@1.3.0(postcss@8.5.8)': + '@csstools/postcss-trigonometric-functions@5.0.2(postcss@8.5.10)': dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 - '@csstools/postcss-stepped-value-functions@1.0.1(postcss@8.5.8)': + '@csstools/postcss-unset-value@5.0.0(postcss@8.5.10)': dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 + postcss: 8.5.10 - '@csstools/postcss-text-decoration-shorthand@1.0.0(postcss@8.5.8)': + '@csstools/selector-resolve-nested@4.0.0(postcss-selector-parser@7.1.1)': dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 + postcss-selector-parser: 7.1.1 - '@csstools/postcss-trigonometric-functions@1.0.2(postcss@8.5.8)': + '@csstools/selector-specificity@6.0.0(postcss-selector-parser@7.1.1)': dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 + postcss-selector-parser: 7.1.1 - '@csstools/postcss-unset-value@1.0.2(postcss@8.5.8)': + '@csstools/utilities@3.0.0(postcss@8.5.10)': dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - '@csstools/selector-specificity@2.2.0(postcss-selector-parser@6.1.2)': - dependencies: - postcss-selector-parser: 6.1.2 - - '@cypress/request@3.0.9': + '@cypress/request@3.0.10': dependencies: aws-sign2: 0.7.0 aws4: 1.13.2 @@ -6465,14 +7364,14 @@ snapshots: combined-stream: 1.0.8 extend: 3.0.2 forever-agent: 0.6.1 - form-data: 4.0.4 + form-data: 4.0.5 http-signature: 1.4.0 is-typedarray: 1.0.0 isstream: 0.1.2 json-stringify-safe: 5.0.1 mime-types: 2.1.35 performance-now: 2.1.0 - qs: 6.14.0 + qs: 6.14.2 safe-buffer: 5.2.1 tough-cookie: 5.1.2 tunnel-agent: 0.6.0 @@ -6485,7 +7384,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@date-fns/utc@1.2.0': {} + '@date-fns/utc@2.1.1': {} '@dicebear/adventurer-neutral@9.4.2(@dicebear/core@9.4.2)': dependencies: @@ -6660,125 +7559,206 @@ snapshots: '@electric-sql/pglite@0.4.1': {} + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@epic-web/invariant@1.0.0': {} - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/aix-ppc64@0.28.0': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-arm64@0.28.0': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/android-arm@0.28.0': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/android-x64@0.28.0': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/darwin-arm64@0.28.0': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/darwin-x64@0.28.0': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/freebsd-arm64@0.28.0': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/freebsd-x64@0.28.0': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/linux-arm64@0.28.0': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/linux-arm@0.28.0': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/linux-ia32@0.28.0': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/linux-loong64@0.28.0': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/linux-mips64el@0.28.0': optional: true - '@formatjs/bigdecimal@0.2.0': {} + '@esbuild/linux-ppc64@0.27.7': + optional: true - '@formatjs/ecma402-abstract@3.2.0': + '@esbuild/linux-ppc64@0.28.0': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.28.0': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.28.0': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/linux-x64@0.28.0': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.28.0': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.28.0': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.28.0': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.28.0': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.28.0': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.28.0': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.28.0': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.28.0': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@esbuild/win32-x64@0.28.0': + optional: true + + '@formatjs/fast-memoize@3.1.2': {} + + '@formatjs/icu-messageformat-parser@3.5.4': dependencies: - '@formatjs/bigdecimal': 0.2.0 - '@formatjs/fast-memoize': 3.1.1 - '@formatjs/intl-localematcher': 0.8.2 + '@formatjs/icu-skeleton-parser': 2.1.4 - '@formatjs/fast-memoize@3.1.1': {} + '@formatjs/icu-skeleton-parser@2.1.4': {} - '@formatjs/icu-messageformat-parser@3.5.3': + '@formatjs/intl-localematcher@0.8.3': dependencies: - '@formatjs/ecma402-abstract': 3.2.0 - '@formatjs/icu-skeleton-parser': 2.1.3 + '@formatjs/fast-memoize': 3.1.2 - '@formatjs/icu-skeleton-parser@2.1.3': + '@hello-pangea/dnd@18.0.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@formatjs/ecma402-abstract': 3.2.0 - - '@formatjs/intl-localematcher@0.8.2': - dependencies: - '@formatjs/fast-memoize': 3.1.1 - - '@hello-pangea/dnd@17.0.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@babel/runtime': 7.28.3 + '@babel/runtime': 7.29.2 css-box-model: 1.2.1 - memoize-one: 6.0.0 raf-schd: 4.0.3 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1) redux: 5.0.1 - use-memo-one: 1.1.3(react@19.2.5) transitivePeerDependencies: - '@types/react' @@ -6899,17 +7879,11 @@ snapshots: dependencies: '@swc/helpers': 0.5.21 - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 @@ -6923,200 +7897,204 @@ snapshots: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.14.1 + js-yaml: 3.14.2 resolve-from: 5.0.0 - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.6': {} - '@jest/console@29.7.0': + '@jest/console@30.3.0': dependencies: - '@jest/types': 29.6.3 - '@types/node': 24.12.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3))': + '@jest/core@30.3.0(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.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.12.0 + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 slash: 3.0.0 - strip-ansi: 6.0.1 transitivePeerDependencies: - babel-plugin-macros + - esbuild-register - supports-color - ts-node '@jest/diff-sequences@30.0.1': {} - '@jest/environment@29.7.0': - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 - jest-mock: 29.7.0 + '@jest/diff-sequences@30.3.0': {} - '@jest/expect-utils@29.7.0': + '@jest/environment@30.3.0': dependencies: - jest-get-type: 29.6.3 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 + jest-mock: 30.3.0 '@jest/expect-utils@30.1.1': dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@29.7.0': + '@jest/expect-utils@30.3.0': dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 + '@jest/get-type': 30.1.0 + + '@jest/expect@30.3.0': + dependencies: + expect: 30.3.0 + jest-snapshot: 30.3.0 transitivePeerDependencies: - supports-color - '@jest/fake-timers@29.7.0': + '@jest/fake-timers@30.3.0': dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 24.12.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.3.2 + '@types/node': 25.6.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 '@jest/get-type@30.1.0': {} - '@jest/globals@29.7.0': + '@jest/globals@30.3.0': dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 transitivePeerDependencies: - supports-color '@jest/pattern@30.0.1': dependencies: - '@types/node': 24.12.0 + '@types/node': 25.6.0 jest-regex-util: 30.0.1 - '@jest/reporters@29.7.0': + '@jest/reporters@30.3.0': dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.30 - '@types/node': 24.12.0 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 25.6.0 chalk: 4.1.2 - collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 + collect-v8-coverage: 1.0.3 + exit-x: 0.2.2 + glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 slash: 3.0.0 string-length: 4.0.2 - strip-ansi: 6.0.1 v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - '@jest/schemas@30.0.5': dependencies: '@sinclair/typebox': 0.34.40 - '@jest/source-map@29.6.3': + '@jest/snapshot-utils@30.3.0': dependencies: - '@jridgewell/trace-mapping': 0.3.30 + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 - '@jest/test-result@29.7.0': + '@jest/test-result@30.3.0': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2 + collect-v8-coverage: 1.0.3 - '@jest/test-sequencer@29.7.0': + '@jest/test-sequencer@30.3.0': dependencies: - '@jest/test-result': 29.7.0 + '@jest/test-result': 30.3.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 + jest-haste-map: 30.3.0 slash: 3.0.0 - '@jest/transform@29.7.0': + '@jest/transform@30.3.0': dependencies: - '@babel/core': 7.28.3 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.30 - babel-plugin-istanbul: 6.1.1 + '@babel/core': 7.29.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 + jest-haste-map: 30.3.0 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 pirates: 4.0.7 slash: 3.0.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - '@jest/types@29.6.3': - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 24.12.0 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - '@jest/types@30.0.5': dependencies: '@jest/pattern': 30.0.1 '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 24.12.0 + '@types/node': 25.6.0 '@types/yargs': 17.0.33 chalk: 4.1.2 + '@jest/types@30.3.0': + dependencies: + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.5 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.6.0 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7132,7 +8110,7 @@ snapshots: '@jridgewell/source-map@0.3.11': dependencies: '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/sourcemap-codec@1.5.5': {} @@ -7153,6 +8131,13 @@ snapshots: '@kurkle/color@0.3.4': {} + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.1 + optional: true + '@netlify/plugin-nextjs@5.15.9': {} '@next/env@16.2.4': {} @@ -7237,7 +8222,7 @@ snapshots: detect-libc: 2.1.2 is-glob: 4.0.3 node-addon-api: 7.1.1 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: '@parcel/watcher-android-arm64': 2.5.6 '@parcel/watcher-darwin-arm64': 2.5.6 @@ -7256,25 +8241,27 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@prisma/adapter-pg@7.6.0': + '@pkgr/core@0.2.9': {} + + '@prisma/adapter-pg@7.7.0': dependencies: - '@prisma/driver-adapter-utils': 7.6.0 + '@prisma/driver-adapter-utils': 7.7.0 '@types/pg': 8.20.0 pg: 8.20.0 postgres-array: 3.0.4 transitivePeerDependencies: - pg-native - '@prisma/client-runtime-utils@7.6.0': {} + '@prisma/client-runtime-utils@7.7.0': {} - '@prisma/client@7.6.0(prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3)': dependencies: - '@prisma/client-runtime-utils': 7.6.0 + '@prisma/client-runtime-utils': 7.7.0 optionalDependencies: - prisma: 7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) - typescript: 5.9.3 + prisma: 7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3) + typescript: 6.0.3 - '@prisma/config@7.6.0': + '@prisma/config@7.7.0': dependencies: c12: 3.1.0 deepmerge-ts: 7.1.5 @@ -7285,9 +8272,9 @@ snapshots: '@prisma/debug@7.2.0': {} - '@prisma/debug@7.6.0': {} + '@prisma/debug@7.7.0': {} - '@prisma/dev@0.24.3(typescript@5.9.3)': + '@prisma/dev@0.24.3(typescript@6.0.3)': dependencies: '@electric-sql/pglite': 0.4.1 '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) @@ -7304,41 +8291,41 @@ snapshots: proper-lockfile: 4.1.2 remeda: 2.33.4 std-env: 3.10.0 - valibot: 1.2.0(typescript@5.9.3) + valibot: 1.2.0(typescript@6.0.3) zeptomatch: 2.1.0 transitivePeerDependencies: - typescript - '@prisma/driver-adapter-utils@7.6.0': + '@prisma/driver-adapter-utils@7.7.0': dependencies: - '@prisma/debug': 7.6.0 + '@prisma/debug': 7.7.0 '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': {} - '@prisma/engines@7.6.0': + '@prisma/engines@7.7.0': dependencies: - '@prisma/debug': 7.6.0 + '@prisma/debug': 7.7.0 '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711 - '@prisma/fetch-engine': 7.6.0 - '@prisma/get-platform': 7.6.0 + '@prisma/fetch-engine': 7.7.0 + '@prisma/get-platform': 7.7.0 - '@prisma/extension-read-replicas@0.5.0(@prisma/client@7.6.0(prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3))': + '@prisma/extension-read-replicas@0.5.0(@prisma/client@7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3))': dependencies: - '@prisma/client': 7.6.0(prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3))(typescript@5.9.3) + '@prisma/client': 7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3))(typescript@6.0.3) - '@prisma/fetch-engine@7.6.0': + '@prisma/fetch-engine@7.7.0': dependencies: - '@prisma/debug': 7.6.0 + '@prisma/debug': 7.7.0 '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711 - '@prisma/get-platform': 7.6.0 + '@prisma/get-platform': 7.7.0 '@prisma/get-platform@7.2.0': dependencies: '@prisma/debug': 7.2.0 - '@prisma/get-platform@7.6.0': + '@prisma/get-platform@7.7.0': dependencies: - '@prisma/debug': 7.6.0 + '@prisma/debug': 7.7.0 '@prisma/query-plan-executor@7.2.0': {} @@ -7451,25 +8438,12 @@ snapshots: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - '@react-spring/animated@10.0.3(react@19.2.5)': - dependencies: - '@react-spring/shared': 10.0.3(react@19.2.5) - '@react-spring/types': 10.0.3 - react: 19.2.5 - '@react-spring/animated@9.7.5(react@19.2.5)': dependencies: '@react-spring/shared': 9.7.5(react@19.2.5) '@react-spring/types': 9.7.5 react: 19.2.5 - '@react-spring/core@10.0.3(react@19.2.5)': - dependencies: - '@react-spring/animated': 10.0.3(react@19.2.5) - '@react-spring/shared': 10.0.3(react@19.2.5) - '@react-spring/types': 10.0.3 - react: 19.2.5 - '@react-spring/core@9.7.5(react@19.2.5)': dependencies: '@react-spring/animated': 9.7.5(react@19.2.5) @@ -7477,35 +8451,16 @@ snapshots: '@react-spring/types': 9.7.5 react: 19.2.5 - '@react-spring/rafz@10.0.3': {} - '@react-spring/rafz@9.7.5': {} - '@react-spring/shared@10.0.3(react@19.2.5)': - dependencies: - '@react-spring/rafz': 10.0.3 - '@react-spring/types': 10.0.3 - react: 19.2.5 - '@react-spring/shared@9.7.5(react@19.2.5)': dependencies: '@react-spring/rafz': 9.7.5 '@react-spring/types': 9.7.5 react: 19.2.5 - '@react-spring/types@10.0.3': {} - '@react-spring/types@9.7.5': {} - '@react-spring/web@10.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@react-spring/animated': 10.0.3(react@19.2.5) - '@react-spring/core': 10.0.3(react@19.2.5) - '@react-spring/shared': 10.0.3(react@19.2.5) - '@react-spring/types': 10.0.3 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - '@react-spring/web@9.7.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@react-spring/animated': 9.7.5(react@19.2.5) @@ -7532,44 +8487,39 @@ snapshots: dependencies: react: 19.2.5 - '@redis/bloom@1.2.0(@redis/client@1.6.1)': + '@redis/bloom@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 1.6.1 + '@redis/client': 5.12.1 - '@redis/client@1.6.1': + '@redis/client@5.12.1': dependencies: cluster-key-slot: 1.1.2 - generic-pool: 3.9.0 - yallist: 4.0.0 - '@redis/graph@1.1.1(@redis/client@1.6.1)': + '@redis/json@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 1.6.1 + '@redis/client': 5.12.1 - '@redis/json@1.0.7(@redis/client@1.6.1)': + '@redis/search@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 1.6.1 + '@redis/client': 5.12.1 - '@redis/search@1.2.0(@redis/client@1.6.1)': + '@redis/time-series@5.12.1(@redis/client@5.12.1)': dependencies: - '@redis/client': 1.6.1 + '@redis/client': 5.12.1 - '@redis/time-series@1.1.0(@redis/client@1.6.1)': - dependencies: - '@redis/client': 1.6.1 - - '@rollup/plugin-alias@5.1.1(rollup@4.60.1)': + '@rollup/plugin-alias@6.0.0(rollup@4.60.1)': optionalDependencies: rollup: 4.60.1 - '@rollup/plugin-commonjs@25.0.8(rollup@4.60.1)': + '@rollup/plugin-commonjs@29.0.2(rollup@4.60.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.60.1) + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) commondir: 1.0.1 estree-walker: 2.0.2 - glob: 8.1.0 + fdir: 6.5.0(picomatch@4.0.4) is-reference: 1.2.1 - magic-string: 0.30.17 + magic-string: 0.30.21 + picomatch: 4.0.4 optionalDependencies: rollup: 4.60.1 @@ -7579,36 +8529,36 @@ snapshots: optionalDependencies: rollup: 4.60.1 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.60.1)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.60.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.60.1) + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.12 optionalDependencies: rollup: 4.60.1 - '@rollup/plugin-replace@5.0.7(rollup@4.60.1)': + '@rollup/plugin-replace@6.0.3(rollup@4.60.1)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.60.1) - magic-string: 0.30.17 + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) + magic-string: 0.30.21 optionalDependencies: rollup: 4.60.1 - '@rollup/plugin-terser@0.4.4(rollup@4.60.1)': + '@rollup/plugin-terser@1.0.0(rollup@4.60.1)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.43.1 + serialize-javascript: 7.0.5 + smob: 1.6.1 + terser: 5.46.1 optionalDependencies: rollup: 4.60.1 - '@rollup/plugin-typescript@12.3.0(rollup@4.60.1)(tslib@2.8.1)(typescript@5.9.3)': + '@rollup/plugin-typescript@12.3.0(rollup@4.60.1)(tslib@2.8.1)(typescript@6.0.3)': dependencies: '@rollup/pluginutils': 5.2.0(rollup@4.60.1) resolve: 1.22.10 - typescript: 5.9.3 + typescript: 6.0.3 optionalDependencies: rollup: 4.60.1 tslib: 2.8.1 @@ -7621,6 +8571,14 @@ snapshots: optionalDependencies: rollup: 4.60.1 + '@rollup/pluginutils@5.3.0(rollup@4.60.1)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.60.1 + '@rollup/rollup-android-arm-eabi@4.60.1': optional: true @@ -7700,8 +8658,6 @@ snapshots: '@schummar/icu-type-parser@1.21.5': {} - '@sinclair/typebox@0.27.8': {} - '@sinclair/typebox@0.34.40': {} '@sindresorhus/merge-streams@2.3.0': {} @@ -7710,7 +8666,7 @@ snapshots: dependencies: type-detect: 4.0.8 - '@sinonjs/fake-timers@10.3.0': + '@sinonjs/fake-timers@15.3.2': dependencies: '@sinonjs/commons': 3.0.1 @@ -7760,12 +8716,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.3) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.3) - '@svgr/cli@8.1.0(typescript@5.9.3)': + '@svgr/cli@8.1.0(typescript@6.0.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - '@svgr/plugin-prettier': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3) + '@svgr/core': 8.1.0(typescript@6.0.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3)) + '@svgr/plugin-prettier': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3))(typescript@6.0.3) camelcase: 6.3.0 chalk: 4.1.2 commander: 9.5.0 @@ -7776,12 +8732,12 @@ snapshots: - supports-color - typescript - '@svgr/core@8.1.0(typescript@5.9.3)': + '@svgr/core@8.1.0(typescript@6.0.3)': dependencies: '@babel/core': 7.28.3 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.3) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.9.3) + cosmiconfig: 8.3.6(typescript@6.0.3) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -7792,76 +8748,84 @@ snapshots: '@babel/types': 7.28.2 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@6.0.3))': dependencies: '@babel/core': 7.28.3 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.3) - '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/core': 8.1.0(typescript@6.0.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-prettier@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + '@svgr/plugin-prettier@8.1.0(@svgr/core@8.1.0(typescript@6.0.3))': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/core': 8.1.0(typescript@6.0.3) deepmerge: 4.3.1 prettier: 2.8.8 - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@6.0.3))(typescript@6.0.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.3) - cosmiconfig: 8.3.6(typescript@5.9.3) + '@svgr/core': 8.1.0(typescript@6.0.3) + cosmiconfig: 8.3.6(typescript@6.0.3) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: - typescript - '@swc/core-darwin-arm64@1.15.11': + '@swc/core-darwin-arm64@1.15.26': optional: true - '@swc/core-darwin-x64@1.15.11': + '@swc/core-darwin-x64@1.15.26': optional: true - '@swc/core-linux-arm-gnueabihf@1.15.11': + '@swc/core-linux-arm-gnueabihf@1.15.26': optional: true - '@swc/core-linux-arm64-gnu@1.15.11': + '@swc/core-linux-arm64-gnu@1.15.26': optional: true - '@swc/core-linux-arm64-musl@1.15.11': + '@swc/core-linux-arm64-musl@1.15.26': optional: true - '@swc/core-linux-x64-gnu@1.15.11': + '@swc/core-linux-ppc64-gnu@1.15.26': optional: true - '@swc/core-linux-x64-musl@1.15.11': + '@swc/core-linux-s390x-gnu@1.15.26': optional: true - '@swc/core-win32-arm64-msvc@1.15.11': + '@swc/core-linux-x64-gnu@1.15.26': optional: true - '@swc/core-win32-ia32-msvc@1.15.11': + '@swc/core-linux-x64-musl@1.15.26': optional: true - '@swc/core-win32-x64-msvc@1.15.11': + '@swc/core-win32-arm64-msvc@1.15.26': optional: true - '@swc/core@1.15.11(@swc/helpers@0.5.21)': + '@swc/core-win32-ia32-msvc@1.15.26': + optional: true + + '@swc/core-win32-x64-msvc@1.15.26': + optional: true + + '@swc/core@1.15.26(@swc/helpers@0.5.21)': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.25 + '@swc/types': 0.1.26 optionalDependencies: - '@swc/core-darwin-arm64': 1.15.11 - '@swc/core-darwin-x64': 1.15.11 - '@swc/core-linux-arm-gnueabihf': 1.15.11 - '@swc/core-linux-arm64-gnu': 1.15.11 - '@swc/core-linux-arm64-musl': 1.15.11 - '@swc/core-linux-x64-gnu': 1.15.11 - '@swc/core-linux-x64-musl': 1.15.11 - '@swc/core-win32-arm64-msvc': 1.15.11 - '@swc/core-win32-ia32-msvc': 1.15.11 - '@swc/core-win32-x64-msvc': 1.15.11 + '@swc/core-darwin-arm64': 1.15.26 + '@swc/core-darwin-x64': 1.15.26 + '@swc/core-linux-arm-gnueabihf': 1.15.26 + '@swc/core-linux-arm64-gnu': 1.15.26 + '@swc/core-linux-arm64-musl': 1.15.26 + '@swc/core-linux-ppc64-gnu': 1.15.26 + '@swc/core-linux-s390x-gnu': 1.15.26 + '@swc/core-linux-x64-gnu': 1.15.26 + '@swc/core-linux-x64-musl': 1.15.26 + '@swc/core-win32-arm64-msvc': 1.15.26 + '@swc/core-win32-ia32-msvc': 1.15.26 + '@swc/core-win32-x64-msvc': 1.15.26 '@swc/helpers': 0.5.21 '@swc/counter@0.1.3': {} @@ -7878,24 +8842,24 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/types@0.1.25': + '@swc/types@0.1.26': dependencies: '@swc/counter': 0.1.3 - '@tanstack/query-core@5.96.0': {} + '@tanstack/query-core@5.99.0': {} - '@tanstack/react-query@5.96.0(react@19.2.5)': + '@tanstack/react-query@5.99.0(react@19.2.5)': dependencies: - '@tanstack/query-core': 5.96.0 + '@tanstack/query-core': 5.99.0 react: 19.2.5 '@trysound/sax@0.2.0': {} - '@ts-morph/common@0.28.1': + '@ts-morph/common@0.29.0': dependencies: - minimatch: 10.0.3 + minimatch: 10.2.5 path-browserify: 1.0.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.16 '@tsconfig/node10@1.0.11': {} @@ -7907,26 +8871,31 @@ snapshots: '@tsconfig/svelte@1.0.13': {} + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.29.0 '@types/css-font-loading-module@0.0.7': {} @@ -7934,16 +8903,12 @@ snapshots: '@types/fs-extra@8.1.5': dependencies: - '@types/node': 24.12.0 + '@types/node': 25.6.0 '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 24.12.0 - - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 24.12.0 + '@types/node': 25.6.0 '@types/istanbul-lib-coverage@2.0.6': {} @@ -7964,15 +8929,15 @@ snapshots: '@types/minimatch@6.0.0': dependencies: - minimatch: 10.0.3 + minimatch: 10.2.5 - '@types/node@24.12.0': + '@types/node@25.6.0': dependencies: - undici-types: 7.16.0 + undici-types: 7.19.2 '@types/pg@8.20.0': dependencies: - '@types/node': 24.12.0 + '@types/node': 25.6.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -7988,10 +8953,12 @@ snapshots: '@types/sinonjs__fake-timers@8.1.1': {} - '@types/sizzle@2.3.9': {} + '@types/sizzle@2.3.10': {} '@types/stack-utils@2.0.3': {} + '@types/tmp@0.2.6': {} + '@types/use-sync-external-store@0.0.6': {} '@types/yargs-parser@21.0.3': {} @@ -8000,9 +8967,13 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + '@types/yauzl@2.10.3': dependencies: - '@types/node': 24.12.0 + '@types/node': 25.6.0 optional: true '@umami/react-zen@0.245.0(@types/react@19.2.14)(immer@11.1.4)(react-aria-components@1.17.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.1.18)(use-sync-external-store@1.6.0(react@19.2.5))': @@ -8025,6 +8996,67 @@ snapshots: - tailwindcss - use-sync-external-store + '@ungap/structured-clone@1.3.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + '@xstate/fsm@1.6.5': {} acorn-walk@8.3.4: @@ -8033,6 +9065,8 @@ snapshots: acorn@8.15.0: {} + acorn@8.16.0: {} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -8072,7 +9106,7 @@ snapshots: anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 arch@2.2.0: {} @@ -8115,20 +9149,17 @@ snapshots: async-function@1.0.0: {} - async@3.2.6: {} - asynckit@0.4.0: {} at-least-node@1.0.0: {} - autoprefixer@10.4.21(postcss@8.5.8): + autoprefixer@10.5.0(postcss@8.5.10): dependencies: - browserslist: 4.25.2 - caniuse-lite: 1.0.30001780 - fraction.js: 4.3.7 - normalize-range: 0.1.2 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001788 + fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -8141,67 +9172,66 @@ snapshots: aws4@1.13.2: {} - babel-jest@29.7.0(@babel/core@7.28.3): + babel-jest@30.3.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.3 - '@jest/transform': 29.7.0 + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.28.3) + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.29.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@6.1.1: + babel-plugin-istanbul@7.0.1: dependencies: - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-instrument: 6.0.3 test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - babel-plugin-jest-hoist@29.6.3: + babel-plugin-jest-hoist@30.3.0: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.28.0 babel-plugin-react-compiler@19.1.0-rc.2: dependencies: '@babel/types': 7.28.2 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.3): + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.3) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.3) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.3) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.3) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.3) + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) - babel-preset-jest@29.6.3(@babel/core@7.28.3): + babel-preset-jest@30.3.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.3 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.3) + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-arraybuffer@1.0.2: {} base64-js@1.5.1: {} @@ -8229,10 +9259,19 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@1.1.14: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -8244,6 +9283,14 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.2) + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.19 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.340 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 @@ -8263,16 +9310,16 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bundle-require@5.1.0(esbuild@0.27.4): + bundle-require@5.1.0(esbuild@0.27.7): dependencies: - esbuild: 0.27.4 + esbuild: 0.27.7 load-tsconfig: 0.2.5 c12@3.1.0: dependencies: chokidar: 4.0.3 confbox: 0.2.4 - defu: 6.1.4 + defu: 6.1.7 dotenv: 16.6.1 exsolve: 1.0.8 giget: 2.0.0 @@ -8342,12 +9389,10 @@ snapshots: dependencies: '@kurkle/color': 0.3.4 - chartjs-adapter-date-fns@3.0.0(chart.js@4.5.1)(date-fns@2.30.0): + chartjs-adapter-date-fns@3.0.0(chart.js@4.5.1)(date-fns@4.1.0): dependencies: chart.js: 4.5.1 - date-fns: 2.30.0 - - check-more-types@2.24.0: {} + date-fns: 4.1.0 chokidar@4.0.3: dependencies: @@ -8355,17 +9400,17 @@ snapshots: chownr@3.0.0: {} - ci-info@3.9.0: {} - ci-info@4.3.0: {} + ci-info@4.4.0: {} + citty@0.1.6: dependencies: consola: 3.4.2 - citty@0.2.1: {} + citty@0.2.2: {} - cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.2.0: {} classnames@2.5.1: {} @@ -8375,11 +9420,11 @@ snapshots: dependencies: restore-cursor: 3.1.0 - cli-table3@0.6.5: + cli-table3@0.6.1: dependencies: string-width: 4.2.3 optionalDependencies: - '@colors/colors': 1.5.0 + colors: 1.4.0 cli-truncate@2.1.0: dependencies: @@ -8402,7 +9447,7 @@ snapshots: code-block-writer@13.0.3: {} - collect-v8-coverage@1.0.2: {} + collect-v8-coverage@1.0.3: {} color-convert@1.9.3: dependencies: @@ -8422,6 +9467,9 @@ snapshots: colorette@2.0.20: {} + colors@1.4.0: + optional: true + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -8463,29 +9511,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@8.3.6(typescript@5.9.3): + cosmiconfig@8.3.6(typescript@6.0.3): dependencies: import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.9.3 - - create-jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(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.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node + typescript: 6.0.3 create-require@1.1.1: {} @@ -8508,27 +9541,29 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-blank-pseudo@3.0.3(postcss@8.5.8): + css-blank-pseudo@8.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 css-box-model@1.2.1: dependencies: tiny-invariant: 1.3.3 - css-declaration-sorter@6.4.1(postcss@8.5.8): + css-declaration-sorter@6.4.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - css-has-pseudo@3.0.4(postcss@8.5.8): + css-has-pseudo@8.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 - css-prefers-color-scheme@6.0.3(postcss@8.5.8): + css-prefers-color-scheme@11.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 css-select@4.3.0: dependencies: @@ -8563,52 +9598,52 @@ snapshots: css-what@6.2.2: {} - cssdb@7.11.2: {} + cssdb@8.8.0: {} cssesc@3.0.0: {} - cssnano-preset-default@5.2.14(postcss@8.5.8): + cssnano-preset-default@5.2.14(postcss@8.5.10): dependencies: - css-declaration-sorter: 6.4.1(postcss@8.5.8) - cssnano-utils: 3.1.0(postcss@8.5.8) - postcss: 8.5.8 - postcss-calc: 8.2.4(postcss@8.5.8) - postcss-colormin: 5.3.1(postcss@8.5.8) - postcss-convert-values: 5.1.3(postcss@8.5.8) - postcss-discard-comments: 5.1.2(postcss@8.5.8) - postcss-discard-duplicates: 5.1.0(postcss@8.5.8) - postcss-discard-empty: 5.1.1(postcss@8.5.8) - postcss-discard-overridden: 5.1.0(postcss@8.5.8) - postcss-merge-longhand: 5.1.7(postcss@8.5.8) - postcss-merge-rules: 5.1.4(postcss@8.5.8) - postcss-minify-font-values: 5.1.0(postcss@8.5.8) - postcss-minify-gradients: 5.1.1(postcss@8.5.8) - postcss-minify-params: 5.1.4(postcss@8.5.8) - postcss-minify-selectors: 5.2.1(postcss@8.5.8) - postcss-normalize-charset: 5.1.0(postcss@8.5.8) - postcss-normalize-display-values: 5.1.0(postcss@8.5.8) - postcss-normalize-positions: 5.1.1(postcss@8.5.8) - postcss-normalize-repeat-style: 5.1.1(postcss@8.5.8) - postcss-normalize-string: 5.1.0(postcss@8.5.8) - postcss-normalize-timing-functions: 5.1.0(postcss@8.5.8) - postcss-normalize-unicode: 5.1.1(postcss@8.5.8) - postcss-normalize-url: 5.1.0(postcss@8.5.8) - postcss-normalize-whitespace: 5.1.1(postcss@8.5.8) - postcss-ordered-values: 5.1.3(postcss@8.5.8) - postcss-reduce-initial: 5.1.2(postcss@8.5.8) - postcss-reduce-transforms: 5.1.0(postcss@8.5.8) - postcss-svgo: 5.1.0(postcss@8.5.8) - postcss-unique-selectors: 5.1.1(postcss@8.5.8) + css-declaration-sorter: 6.4.1(postcss@8.5.10) + cssnano-utils: 3.1.0(postcss@8.5.10) + postcss: 8.5.10 + postcss-calc: 8.2.4(postcss@8.5.10) + postcss-colormin: 5.3.1(postcss@8.5.10) + postcss-convert-values: 5.1.3(postcss@8.5.10) + postcss-discard-comments: 5.1.2(postcss@8.5.10) + postcss-discard-duplicates: 5.1.0(postcss@8.5.10) + postcss-discard-empty: 5.1.1(postcss@8.5.10) + postcss-discard-overridden: 5.1.0(postcss@8.5.10) + postcss-merge-longhand: 5.1.7(postcss@8.5.10) + postcss-merge-rules: 5.1.4(postcss@8.5.10) + postcss-minify-font-values: 5.1.0(postcss@8.5.10) + postcss-minify-gradients: 5.1.1(postcss@8.5.10) + postcss-minify-params: 5.1.4(postcss@8.5.10) + postcss-minify-selectors: 5.2.1(postcss@8.5.10) + postcss-normalize-charset: 5.1.0(postcss@8.5.10) + postcss-normalize-display-values: 5.1.0(postcss@8.5.10) + postcss-normalize-positions: 5.1.1(postcss@8.5.10) + postcss-normalize-repeat-style: 5.1.1(postcss@8.5.10) + postcss-normalize-string: 5.1.0(postcss@8.5.10) + postcss-normalize-timing-functions: 5.1.0(postcss@8.5.10) + postcss-normalize-unicode: 5.1.1(postcss@8.5.10) + postcss-normalize-url: 5.1.0(postcss@8.5.10) + postcss-normalize-whitespace: 5.1.1(postcss@8.5.10) + postcss-ordered-values: 5.1.3(postcss@8.5.10) + postcss-reduce-initial: 5.1.2(postcss@8.5.10) + postcss-reduce-transforms: 5.1.0(postcss@8.5.10) + postcss-svgo: 5.1.0(postcss@8.5.10) + postcss-unique-selectors: 5.1.1(postcss@8.5.10) - cssnano-utils@3.1.0(postcss@8.5.8): + cssnano-utils@3.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - cssnano@5.1.15(postcss@8.5.8): + cssnano@5.1.15(postcss@8.5.10): dependencies: - cssnano-preset-default: 5.2.14(postcss@8.5.8) + cssnano-preset-default: 5.2.14(postcss@8.5.10) lilconfig: 2.1.0 - postcss: 8.5.8 + postcss: 8.5.10 yaml: 1.10.2 csso@4.2.0: @@ -8621,25 +9656,25 @@ snapshots: csstype@3.2.3: {} - cypress@13.17.0: + cypress@15.14.0: dependencies: - '@cypress/request': 3.0.9 + '@cypress/request': 3.0.10 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) '@types/sinonjs__fake-timers': 8.1.1 - '@types/sizzle': 2.3.9 + '@types/sizzle': 2.3.10 + '@types/tmp': 0.2.6 arch: 2.2.0 blob-util: 2.0.2 bluebird: 3.7.2 buffer: 5.7.1 cachedir: 2.4.0 chalk: 4.1.2 - check-more-types: 2.24.0 - ci-info: 4.3.0 + ci-info: 4.4.0 cli-cursor: 3.1.0 - cli-table3: 0.6.5 + cli-table3: 0.6.1 commander: 6.2.1 common-tags: 1.8.2 - dayjs: 1.11.13 + dayjs: 1.11.20 debug: 4.4.3(supports-color@8.1.1) enquirer: 2.4.1 eventemitter2: 6.4.7 @@ -8648,11 +9683,10 @@ snapshots: extract-zip: 2.0.1(supports-color@8.1.1) figures: 3.2.0 fs-extra: 9.1.0 - getos: 3.2.1 + hasha: 5.2.2 is-installed-globally: 0.4.0 - lazy-ass: 1.6.0 listr2: 3.14.0(enquirer@2.4.1) - lodash: 4.17.21 + lodash: 4.18.1 log-symbols: 4.1.0 minimist: 1.2.8 ospath: 1.2.2 @@ -8660,10 +9694,11 @@ snapshots: process: 0.11.10 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.7.4 supports-color: 8.1.1 + systeminformation: 5.31.5 tmp: 0.2.5 tree-kill: 1.2.2 + tslib: 1.14.1 untildify: 4.0.0 yauzl: 2.10.0 @@ -8737,15 +9772,13 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - date-fns-tz@1.3.8(date-fns@2.30.0): + date-fns-tz@3.2.0(date-fns@4.1.0): dependencies: - date-fns: 2.30.0 + date-fns: 4.1.0 - date-fns@2.30.0: - dependencies: - '@babel/runtime': 7.28.3 + date-fns@4.1.0: {} - dayjs@1.11.13: {} + dayjs@1.11.20: {} debug@3.2.7(supports-color@8.1.1): dependencies: @@ -8759,7 +9792,7 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - dedent@1.6.0: {} + dedent@1.7.2: {} deepmerge-ts@7.1.5: {} @@ -8777,18 +9810,7 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} - - del@6.1.1: - dependencies: - globby: 11.1.0 - graceful-fs: 4.2.11 - is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 - rimraf: 3.0.2 - slash: 3.0.0 + defu@6.1.7: {} del@8.0.1: dependencies: @@ -8814,8 +9836,6 @@ snapshots: detect-newline@3.1.0: {} - diff-sequences@29.6.3: {} - diff@4.0.2: {} dir-glob@3.0.1: @@ -8864,7 +9884,7 @@ snapshots: dotenv-cli@11.0.0: dependencies: cross-spawn: 7.0.6 - dotenv: 17.3.1 + dotenv: 17.4.2 dotenv-expand: 12.0.3 minimist: 1.2.8 @@ -8874,7 +9894,7 @@ snapshots: dotenv@16.6.1: {} - dotenv@17.3.1: {} + dotenv@17.4.2: {} dunder-proto@1.0.1: dependencies: @@ -8900,6 +9920,8 @@ snapshots: electron-to-chromium@1.5.202: {} + electron-to-chromium@1.5.340: {} + emittery@0.13.1: {} emoji-regex@8.0.0: {} @@ -9005,34 +10027,63 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.27.4: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + esbuild@0.28.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 escalade@3.2.0: {} @@ -9078,15 +10129,7 @@ snapshots: dependencies: pify: 2.3.0 - exit@0.1.2: {} - - expect@29.7.0: - dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + exit-x@0.2.2: {} expect@30.1.1: dependencies: @@ -9097,6 +10140,15 @@ snapshots: jest-mock: 30.0.5 jest-util: 30.0.5 + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + exsolve@1.0.8: {} extend@3.0.2: {} @@ -9143,9 +10195,9 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 fetch-blob@3.2.0: dependencies: @@ -9184,19 +10236,28 @@ snapshots: forever-agent@0.6.1: {} - form-data@4.0.4: + form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.3 mime-types: 2.1.35 formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 - fraction.js@4.3.7: {} + fraction.js@5.3.4: {} + + framer-motion@12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + motion-dom: 12.38.0 + motion-utils: 12.36.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) fs-extra@8.1.0: dependencies: @@ -9237,8 +10298,6 @@ snapshots: dependencies: loader-utils: 3.3.1 - generic-pool@3.9.0: {} - gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -9267,7 +10326,7 @@ snapshots: get-stream@5.2.0: dependencies: - pump: 3.0.3 + pump: 3.0.4 get-stream@6.0.1: {} @@ -9281,10 +10340,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - getos@3.2.1: - dependencies: - async: 3.2.6 - getpass@0.1.7: dependencies: assert-plus: 1.0.0 @@ -9293,7 +10348,7 @@ snapshots: dependencies: citty: 0.1.6 consola: 3.4.2 - defu: 6.1.4 + defu: 6.1.7 node-fetch-native: 1.6.7 nypm: 0.6.5 pathe: 2.0.3 @@ -9348,15 +10403,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globby@14.1.0: dependencies: '@sindresorhus/merge-streams': 2.3.0 @@ -9374,7 +10420,7 @@ snapshots: graphmatch@1.1.1: {} - handlebars@4.7.8: + handlebars@4.7.9: dependencies: minimist: 1.2.8 neo-async: 2.6.2 @@ -9403,10 +10449,19 @@ snapshots: dependencies: has-symbols: 1.1.0 + hasha@5.2.2: + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + hono@4.12.9: {} hosted-git-info@2.8.9: {} @@ -9431,13 +10486,13 @@ snapshots: icss-replace-symbols@1.1.0: {} - icss-utils@5.1.0(postcss@8.5.8): + icss-utils@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - icu-minify@4.8.4: + icu-minify@4.9.1: dependencies: - '@formatjs/icu-messageformat-parser': 3.5.3 + '@formatjs/icu-messageformat-parser': 3.5.4 ieee754@1.2.1: {} @@ -9488,11 +10543,10 @@ snapshots: internmap@1.0.1: {} - intl-messageformat@11.2.0: + intl-messageformat@11.2.1: dependencies: - '@formatjs/ecma402-abstract': 3.2.0 - '@formatjs/fast-memoize': 3.1.1 - '@formatjs/icu-messageformat-parser': 3.5.3 + '@formatjs/fast-memoize': 3.1.2 + '@formatjs/icu-messageformat-parser': 3.5.4 ipaddr.js@2.3.0: {} @@ -9523,9 +10577,9 @@ snapshots: is-callable@1.2.7: {} - is-ci@3.0.1: + is-ci@4.1.0: dependencies: - ci-info: 3.9.0 + ci-info: 4.4.0 is-core-module@2.16.1: dependencies: @@ -9542,7 +10596,7 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-docker@3.0.0: {} + is-docker@4.0.0: {} is-extglob@2.1.1: {} @@ -9570,7 +10624,7 @@ snapshots: global-dirs: 3.0.1 is-path-inside: 3.0.3 - is-localhost-ip@2.0.0: {} + is-localhost-ip@3.0.1: {} is-map@2.0.3: {} @@ -9585,8 +10639,6 @@ snapshots: is-number@7.0.0: {} - is-path-cwd@2.2.0: {} - is-path-cwd@3.0.0: {} is-path-inside@3.0.3: {} @@ -9652,7 +10704,7 @@ snapshots: isarray@2.0.5: {} - isbot@5.1.37: {} + isbot@5.1.39: {} isexe@2.0.0: {} @@ -9660,21 +10712,11 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.3 - '@babel/parser': 7.28.3 - '@istanbuljs/schema': 0.1.3 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 semver: 7.7.4 transitivePeerDependencies: @@ -9686,15 +10728,15 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@5.0.6: dependencies: + '@jridgewell/trace-mapping': 0.3.31 debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 transitivePeerDependencies: - supports-color - istanbul-reports@3.1.7: + istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 @@ -9705,95 +10747,89 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jest-changed-files@29.7.0: + jest-changed-files@30.3.0: dependencies: execa: 5.1.1 - jest-util: 29.7.0 + jest-util: 30.3.0 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 chalk: 4.1.2 co: 4.6.0 - dedent: 1.6.0 + dedent: 1.7.2 is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)): + jest-cli@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.3.0(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - exit: 0.1.2 + exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - jest-util: 29.7.0 - jest-validate: 29.7.0 + jest-config: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) + jest-util: 30.3.0 + jest-validate: 30.3.0 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node - jest-config@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)): + jest-config@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)): dependencies: - '@babel/core': 7.28.3 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.3) + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) chalk: 4.1.2 - ci-info: 3.9.0 + ci-info: 4.4.0 deepmerge: 4.3.1 - glob: 7.2.3 + glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 parse-json: 5.2.0 - pretty-format: 29.7.0 + pretty-format: 30.3.0 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 24.12.0 - ts-node: 10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3) + '@types/node': 25.6.0 + ts-node: 10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-diff@29.7.0: - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - jest-diff@30.1.1: dependencies: '@jest/diff-sequences': 30.0.1 @@ -9801,56 +10837,54 @@ snapshots: chalk: 4.1.2 pretty-format: 30.0.5 - jest-docblock@29.7.0: + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@30.2.0: dependencies: detect-newline: 3.1.0 - jest-each@29.7.0: + jest-each@30.3.0: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 - jest-environment-node@29.7.0: + jest-environment-node@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 - jest-get-type@29.6.3: {} - - jest-haste-map@29.7.0: + jest-haste-map@30.3.0: dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 24.12.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.4 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - jest-leak-detector@29.7.0: + jest-leak-detector@30.3.0: dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-matcher-utils@29.7.0: - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 jest-matcher-utils@30.1.1: dependencies: @@ -9859,17 +10893,12 @@ snapshots: jest-diff: 30.1.1 pretty-format: 30.0.5 - jest-message-util@29.7.0: + jest-matcher-utils@30.3.0: dependencies: - '@babel/code-frame': 7.29.0 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 + '@jest/get-type': 30.1.0 chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 + jest-diff: 30.3.0 + pretty-format: 30.3.0 jest-message-util@30.1.0: dependencies: @@ -9883,177 +10912,190 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 - jest-mock@29.7.0: + jest-message-util@30.3.0: dependencies: - '@jest/types': 29.6.3 - '@types/node': 24.12.0 - jest-util: 29.7.0 + '@babel/code-frame': 7.29.0 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 jest-mock@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 24.12.0 + '@types/node': 25.6.0 jest-util: 30.0.5 - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: - jest-resolve: 29.7.0 + jest-mock@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.6.0 + jest-util: 30.3.0 - jest-regex-util@29.6.3: {} + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 jest-regex-util@30.0.1: {} - jest-resolve-dependencies@29.7.0: + jest-resolve-dependencies@30.3.0: dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 transitivePeerDependencies: - supports-color - jest-resolve@29.7.0: + jest-resolve@30.3.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.10 - resolve.exports: 2.0.3 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 slash: 3.0.0 + unrs-resolver: 1.11.1 - jest-runner@29.7.0: + jest-runner@30.3.0: dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 chalk: 4.1.2 emittery: 0.13.1 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 p-limit: 3.1.0 source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - jest-runtime@29.7.0: + jest-runtime@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 chalk: 4.1.2 - cjs-module-lexer: 1.4.3 - collect-v8-coverage: 1.0.2 - glob: 7.2.3 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3 + glob: 10.5.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - jest-snapshot@29.7.0: + jest-snapshot@30.3.0: dependencies: - '@babel/core': 7.28.3 - '@babel/generator': 7.28.3 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) - '@babel/types': 7.28.2 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.3) + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) chalk: 4.1.2 - expect: 29.7.0 + expect: 30.3.0 graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 semver: 7.7.4 + synckit: 0.11.12 transitivePeerDependencies: - supports-color - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 24.12.0 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - jest-util@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 24.12.0 + '@types/node': 25.6.0 chalk: 4.1.2 ci-info: 4.3.0 graceful-fs: 4.2.11 picomatch: 4.0.3 - jest-validate@29.7.0: + jest-util@30.3.0: dependencies: - '@jest/types': 29.6.3 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-validate@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 leven: 3.1.0 - pretty-format: 29.7.0 + pretty-format: 30.3.0 - jest-watcher@29.7.0: + jest-watcher@30.3.0: dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 24.12.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.6.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.7.0 + jest-util: 30.3.0 string-length: 4.0.2 - jest-worker@29.7.0: + jest-worker@30.3.0: dependencies: - '@types/node': 24.12.0 - jest-util: 29.7.0 + '@types/node': 25.6.0 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.3.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)): + jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - '@jest/types': 29.6.3 + '@jest/core': 30.3.0(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) + '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) + jest-cli: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node @@ -10063,7 +11105,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@3.14.1: + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 @@ -10140,8 +11182,6 @@ snapshots: kleur@3.0.3: {} - lazy-ass@1.6.0: {} - leven@3.1.0: {} lie@3.3.0: @@ -10202,7 +11242,7 @@ snapshots: lodash.uniq@4.5.0: {} - lodash@4.17.21: {} + lodash@4.18.1: {} log-symbols@4.1.0: dependencies: @@ -10238,14 +11278,10 @@ snapshots: dependencies: react: 19.2.5 - lucide-react@1.7.0(react@19.2.5): + lucide-react@1.8.0(react@19.2.5): dependencies: react: 19.2.5 - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -10262,10 +11298,10 @@ snapshots: math-intrinsics@1.1.0: {} - maxmind@5.0.5: + maxmind@5.0.6: dependencies: mmdb-lib: 3.0.2 - tiny-lru: 11.4.7 + tiny-lru: 13.0.0 mdn-data@2.0.14: {} @@ -10273,10 +11309,6 @@ snapshots: mdn-data@2.0.30: {} - memoize-one@5.2.1: {} - - memoize-one@6.0.0: {} - memorystream@0.3.1: {} merge-stream@2.0.0: {} @@ -10286,7 +11318,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.52.0: {} @@ -10296,14 +11328,18 @@ snapshots: mimic-fn@2.1.0: {} - minimatch@10.0.3: + minimatch@10.2.5: dependencies: - '@isaacs/brace-expansion': 5.0.0 + brace-expansion: 5.0.5 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.14 + minimatch@5.1.6: dependencies: brace-expansion: 2.0.2 @@ -10324,13 +11360,27 @@ snapshots: mlly@1.8.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.1 mmdb-lib@3.0.2: {} + motion-dom@12.38.0: + dependencies: + motion-utils: 12.36.0 + + motion-utils@12.36.0: {} + + motion@12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + dependencies: + framer-motion: 12.38.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + tslib: 2.8.1 + optionalDependencies: + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + ms@2.1.3: {} mysql2@3.15.3: @@ -10357,32 +11407,34 @@ snapshots: nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} + natural-compare@1.4.0: {} negotiator@1.0.0: {} neo-async@2.6.2: {} - next-intl-swc-plugin-extractor@4.8.4: {} + next-intl-swc-plugin-extractor@4.9.1: {} - next-intl@4.8.3(@swc/helpers@0.5.21)(next@16.2.4(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + next-intl@4.9.1(@swc/helpers@0.5.21)(next@16.2.4(@babel/core@7.29.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(typescript@6.0.3): dependencies: - '@formatjs/intl-localematcher': 0.8.2 + '@formatjs/intl-localematcher': 0.8.3 '@parcel/watcher': 2.5.6 - '@swc/core': 1.15.11(@swc/helpers@0.5.21) - icu-minify: 4.8.4 + '@swc/core': 1.15.26(@swc/helpers@0.5.21) + icu-minify: 4.9.1 negotiator: 1.0.0 - next: 16.2.4(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - next-intl-swc-plugin-extractor: 4.8.4 + next: 16.2.4(@babel/core@7.29.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next-intl-swc-plugin-extractor: 4.9.1 po-parser: 2.1.1 react: 19.2.5 - use-intl: 4.8.4(react@19.2.5) + use-intl: 4.9.1(react@19.2.5) optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@swc/helpers' - next@16.2.4(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + next@16.2.4(@babel/core@7.29.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@next/env': 16.2.4 '@swc/helpers': 0.5.15 @@ -10391,7 +11443,7 @@ snapshots: postcss: 8.4.31 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.5) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.5) optionalDependencies: '@next/swc-darwin-arm64': 16.2.4 '@next/swc-darwin-x64': 16.2.4 @@ -10430,17 +11482,19 @@ snapshots: node-releases@2.0.19: {} + node-releases@2.0.37: {} + + non-error@0.1.0: {} + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.10 + resolve: 1.22.12 semver: 5.7.2 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} - normalize-range@0.1.2: {} - normalize-url@6.1.0: {} npm-run-all@4.1.5: @@ -10465,9 +11519,9 @@ snapshots: nypm@0.6.5: dependencies: - citty: 0.2.1 + citty: 0.2.2 pathe: 2.0.3 - tinyexec: 1.0.4 + tinyexec: 1.1.1 object-assign@4.1.1: {} @@ -10625,10 +11679,12 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} picomatch@4.0.3: {} + picomatch@4.0.4: {} + pidtree@0.3.1: {} pify@2.3.0: {} @@ -10659,391 +11715,425 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-attribute-case-insensitive@5.0.2(postcss@8.5.8): + postcss-attribute-case-insensitive@8.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 - postcss-calc@8.2.4(postcss@8.5.8): + postcss-calc@8.2.4(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - postcss-clamp@4.1.0(postcss@8.5.8): + postcss-clamp@4.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-color-functional-notation@4.2.4(postcss@8.5.8): + postcss-color-functional-notation@8.0.3(postcss@8.5.10): dependencies: - postcss: 8.5.8 + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 + + postcss-color-hex-alpha@11.0.0(postcss@8.5.10): + dependencies: + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-color-hex-alpha@8.0.4(postcss@8.5.8): + postcss-color-rebeccapurple@11.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-color-rebeccapurple@7.1.1(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - - postcss-colormin@5.3.1(postcss@8.5.8): + postcss-colormin@5.3.1(postcss@8.5.10): dependencies: browserslist: 4.25.2 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-convert-values@5.1.3(postcss@8.5.8): + postcss-convert-values@5.1.3(postcss@8.5.10): dependencies: browserslist: 4.25.2 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-custom-media@8.0.2(postcss@8.5.8): + postcss-custom-media@12.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + '@csstools/cascade-layer-name-parser': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/media-query-list-parser': 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + postcss: 8.5.10 + + postcss-custom-properties@15.0.1(postcss@8.5.10): + dependencies: + '@csstools/cascade-layer-name-parser': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-custom-properties@12.1.11(postcss@8.5.8): + postcss-custom-selectors@9.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + '@csstools/cascade-layer-name-parser': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + + postcss-dir-pseudo-class@10.0.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 + + postcss-discard-comments@5.1.2(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + + postcss-discard-duplicates@5.1.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + + postcss-discard-empty@5.1.1(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + + postcss-discard-overridden@5.1.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + + postcss-double-position-gradients@7.0.0(postcss@8.5.10): + dependencies: + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-custom-selectors@6.0.3(postcss@8.5.8): + postcss-flexbugs-fixes@5.0.2(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 - postcss-dir-pseudo-class@6.0.5(postcss@8.5.8): + postcss-focus-visible@11.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 - postcss-discard-comments@5.1.2(postcss@8.5.8): + postcss-focus-within@10.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 - postcss-discard-duplicates@5.1.0(postcss@8.5.8): + postcss-font-variant@5.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-discard-empty@5.1.1(postcss@8.5.8): + postcss-gap-properties@7.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-discard-overridden@5.1.0(postcss@8.5.8): + postcss-image-set-function@8.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - - postcss-double-position-gradients@3.1.2(postcss@8.5.8): - dependencies: - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - postcss: 8.5.8 + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-env-function@4.0.6(postcss@8.5.8): + postcss-import@16.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - - postcss-flexbugs-fixes@5.0.2(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-focus-visible@6.0.4(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 - - postcss-focus-within@5.0.4(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 - - postcss-font-variant@5.0.0(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-gap-properties@3.0.5(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-image-set-function@4.0.7(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - - postcss-import@15.1.0(postcss@8.5.8): - dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.12 - postcss-initial@4.0.1(postcss@8.5.8): + postcss-lab-function@8.0.3(postcss@8.5.10): dependencies: - postcss: 8.5.8 + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/utilities': 3.0.0(postcss@8.5.10) + postcss: 8.5.10 - postcss-lab-function@4.2.1(postcss@8.5.8): - dependencies: - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - - postcss-load-config@3.1.4(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)): + postcss-load-config@3.1.4(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: - postcss: 8.5.8 - ts-node: 10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3) + postcss: 8.5.10 + ts-node: 10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3) - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.1): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.8 + postcss: 8.5.10 tsx: 4.21.0 yaml: 2.8.1 - postcss-logical@5.0.4(postcss@8.5.8): + postcss-logical@9.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - - postcss-media-minmax@5.0.0(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-merge-longhand@5.1.7(postcss@8.5.8): - dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - stylehacks: 5.1.1(postcss@8.5.8) - postcss-merge-rules@5.1.4(postcss@8.5.8): + postcss-merge-longhand@5.1.7(postcss@8.5.10): + dependencies: + postcss: 8.5.10 + postcss-value-parser: 4.2.0 + stylehacks: 5.1.1(postcss@8.5.10) + + postcss-merge-rules@5.1.4(postcss@8.5.10): dependencies: browserslist: 4.25.2 caniuse-api: 3.0.0 - cssnano-utils: 3.1.0(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 3.1.0(postcss@8.5.10) + postcss: 8.5.10 postcss-selector-parser: 6.1.2 - postcss-minify-font-values@5.1.0(postcss@8.5.8): + postcss-minify-font-values@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-minify-gradients@5.1.1(postcss@8.5.8): + postcss-minify-gradients@5.1.1(postcss@8.5.10): dependencies: colord: 2.9.3 - cssnano-utils: 3.1.0(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 3.1.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-minify-params@5.1.4(postcss@8.5.8): + postcss-minify-params@5.1.4(postcss@8.5.10): dependencies: browserslist: 4.25.2 - cssnano-utils: 3.1.0(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 3.1.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-minify-selectors@5.2.1(postcss@8.5.8): + postcss-minify-selectors@5.2.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 - postcss-modules-extract-imports@3.1.0(postcss@8.5.8): + postcss-modules-extract-imports@3.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-modules-local-by-default@4.2.0(postcss@8.5.8): + postcss-modules-local-by-default@4.2.0(postcss@8.5.10): dependencies: - icss-utils: 5.1.0(postcss@8.5.8) - postcss: 8.5.8 + icss-utils: 5.1.0(postcss@8.5.10) + postcss: 8.5.10 postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 - postcss-modules-scope@3.2.1(postcss@8.5.8): + postcss-modules-scope@3.2.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 7.1.0 - postcss-modules-values@4.0.0(postcss@8.5.8): + postcss-modules-values@4.0.0(postcss@8.5.10): dependencies: - icss-utils: 5.1.0(postcss@8.5.8) - postcss: 8.5.8 + icss-utils: 5.1.0(postcss@8.5.10) + postcss: 8.5.10 - postcss-modules@4.3.1(postcss@8.5.8): + postcss-modules@4.3.1(postcss@8.5.10): dependencies: generic-names: 4.0.0 icss-replace-symbols: 1.1.0 lodash.camelcase: 4.3.0 - postcss: 8.5.8 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.8) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.8) - postcss-modules-scope: 3.2.1(postcss@8.5.8) - postcss-modules-values: 4.0.0(postcss@8.5.8) + postcss: 8.5.10 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.10) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.10) + postcss-modules-scope: 3.2.1(postcss@8.5.10) + postcss-modules-values: 4.0.0(postcss@8.5.10) string-hash: 1.1.3 - postcss-nesting@10.2.0(postcss@8.5.8): + postcss-nesting@14.0.0(postcss@8.5.10): dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.2) - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + '@csstools/selector-resolve-nested': 4.0.0(postcss-selector-parser@7.1.1) + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 - postcss-normalize-charset@5.1.0(postcss@8.5.8): + postcss-normalize-charset@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-normalize-display-values@5.1.0(postcss@8.5.8): + postcss-normalize-display-values@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-positions@5.1.1(postcss@8.5.8): + postcss-normalize-positions@5.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@5.1.1(postcss@8.5.8): + postcss-normalize-repeat-style@5.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-string@5.1.0(postcss@8.5.8): + postcss-normalize-string@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@5.1.0(postcss@8.5.8): + postcss-normalize-timing-functions@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@5.1.1(postcss@8.5.8): + postcss-normalize-unicode@5.1.1(postcss@8.5.10): dependencies: browserslist: 4.25.2 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-url@5.1.0(postcss@8.5.8): + postcss-normalize-url@5.1.0(postcss@8.5.10): dependencies: normalize-url: 6.1.0 - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@5.1.1(postcss@8.5.8): + postcss-normalize-whitespace@5.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-opacity-percentage@1.1.3(postcss@8.5.8): + postcss-opacity-percentage@3.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-ordered-values@5.1.3(postcss@8.5.8): + postcss-ordered-values@5.1.3(postcss@8.5.10): dependencies: - cssnano-utils: 3.1.0(postcss@8.5.8) - postcss: 8.5.8 + cssnano-utils: 3.1.0(postcss@8.5.10) + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-overflow-shorthand@3.0.4(postcss@8.5.8): + postcss-overflow-shorthand@7.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-page-break@3.0.4(postcss@8.5.8): + postcss-page-break@3.0.4(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-place@7.0.5(postcss@8.5.8): + postcss-place@11.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-preset-env@7.8.3(postcss@8.5.8): + postcss-preset-env@11.2.1(postcss@8.5.10): dependencies: - '@csstools/postcss-cascade-layers': 1.1.1(postcss@8.5.8) - '@csstools/postcss-color-function': 1.1.1(postcss@8.5.8) - '@csstools/postcss-font-format-keywords': 1.0.1(postcss@8.5.8) - '@csstools/postcss-hwb-function': 1.0.2(postcss@8.5.8) - '@csstools/postcss-ic-unit': 1.0.1(postcss@8.5.8) - '@csstools/postcss-is-pseudo-class': 2.0.7(postcss@8.5.8) - '@csstools/postcss-nested-calc': 1.0.0(postcss@8.5.8) - '@csstools/postcss-normalize-display-values': 1.0.1(postcss@8.5.8) - '@csstools/postcss-oklab-function': 1.1.1(postcss@8.5.8) - '@csstools/postcss-progressive-custom-properties': 1.3.0(postcss@8.5.8) - '@csstools/postcss-stepped-value-functions': 1.0.1(postcss@8.5.8) - '@csstools/postcss-text-decoration-shorthand': 1.0.0(postcss@8.5.8) - '@csstools/postcss-trigonometric-functions': 1.0.2(postcss@8.5.8) - '@csstools/postcss-unset-value': 1.0.2(postcss@8.5.8) - autoprefixer: 10.4.21(postcss@8.5.8) - browserslist: 4.25.2 - css-blank-pseudo: 3.0.3(postcss@8.5.8) - css-has-pseudo: 3.0.4(postcss@8.5.8) - css-prefers-color-scheme: 6.0.3(postcss@8.5.8) - cssdb: 7.11.2 - postcss: 8.5.8 - postcss-attribute-case-insensitive: 5.0.2(postcss@8.5.8) - postcss-clamp: 4.1.0(postcss@8.5.8) - postcss-color-functional-notation: 4.2.4(postcss@8.5.8) - postcss-color-hex-alpha: 8.0.4(postcss@8.5.8) - postcss-color-rebeccapurple: 7.1.1(postcss@8.5.8) - postcss-custom-media: 8.0.2(postcss@8.5.8) - postcss-custom-properties: 12.1.11(postcss@8.5.8) - postcss-custom-selectors: 6.0.3(postcss@8.5.8) - postcss-dir-pseudo-class: 6.0.5(postcss@8.5.8) - postcss-double-position-gradients: 3.1.2(postcss@8.5.8) - postcss-env-function: 4.0.6(postcss@8.5.8) - postcss-focus-visible: 6.0.4(postcss@8.5.8) - postcss-focus-within: 5.0.4(postcss@8.5.8) - postcss-font-variant: 5.0.0(postcss@8.5.8) - postcss-gap-properties: 3.0.5(postcss@8.5.8) - postcss-image-set-function: 4.0.7(postcss@8.5.8) - postcss-initial: 4.0.1(postcss@8.5.8) - postcss-lab-function: 4.2.1(postcss@8.5.8) - postcss-logical: 5.0.4(postcss@8.5.8) - postcss-media-minmax: 5.0.0(postcss@8.5.8) - postcss-nesting: 10.2.0(postcss@8.5.8) - postcss-opacity-percentage: 1.1.3(postcss@8.5.8) - postcss-overflow-shorthand: 3.0.4(postcss@8.5.8) - postcss-page-break: 3.0.4(postcss@8.5.8) - postcss-place: 7.0.5(postcss@8.5.8) - postcss-pseudo-class-any-link: 7.1.6(postcss@8.5.8) - postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.8) - postcss-selector-not: 6.0.1(postcss@8.5.8) - postcss-value-parser: 4.2.0 + '@csstools/postcss-alpha-function': 2.0.4(postcss@8.5.10) + '@csstools/postcss-cascade-layers': 6.0.0(postcss@8.5.10) + '@csstools/postcss-color-function': 5.0.3(postcss@8.5.10) + '@csstools/postcss-color-function-display-p3-linear': 2.0.3(postcss@8.5.10) + '@csstools/postcss-color-mix-function': 4.0.3(postcss@8.5.10) + '@csstools/postcss-color-mix-variadic-function-arguments': 2.0.3(postcss@8.5.10) + '@csstools/postcss-content-alt-text': 3.0.0(postcss@8.5.10) + '@csstools/postcss-contrast-color-function': 3.0.3(postcss@8.5.10) + '@csstools/postcss-exponential-functions': 3.0.2(postcss@8.5.10) + '@csstools/postcss-font-format-keywords': 5.0.0(postcss@8.5.10) + '@csstools/postcss-font-width-property': 1.0.0(postcss@8.5.10) + '@csstools/postcss-gamut-mapping': 3.0.3(postcss@8.5.10) + '@csstools/postcss-gradients-interpolation-method': 6.0.3(postcss@8.5.10) + '@csstools/postcss-hwb-function': 5.0.3(postcss@8.5.10) + '@csstools/postcss-ic-unit': 5.0.0(postcss@8.5.10) + '@csstools/postcss-initial': 3.0.0(postcss@8.5.10) + '@csstools/postcss-is-pseudo-class': 6.0.0(postcss@8.5.10) + '@csstools/postcss-light-dark-function': 3.0.0(postcss@8.5.10) + '@csstools/postcss-logical-float-and-clear': 4.0.0(postcss@8.5.10) + '@csstools/postcss-logical-overflow': 3.0.0(postcss@8.5.10) + '@csstools/postcss-logical-overscroll-behavior': 3.0.0(postcss@8.5.10) + '@csstools/postcss-logical-resize': 4.0.0(postcss@8.5.10) + '@csstools/postcss-logical-viewport-units': 4.0.0(postcss@8.5.10) + '@csstools/postcss-media-minmax': 3.0.2(postcss@8.5.10) + '@csstools/postcss-media-queries-aspect-ratio-number-values': 4.0.0(postcss@8.5.10) + '@csstools/postcss-mixins': 1.0.0(postcss@8.5.10) + '@csstools/postcss-nested-calc': 5.0.0(postcss@8.5.10) + '@csstools/postcss-normalize-display-values': 5.0.1(postcss@8.5.10) + '@csstools/postcss-oklab-function': 5.0.3(postcss@8.5.10) + '@csstools/postcss-position-area-property': 2.0.0(postcss@8.5.10) + '@csstools/postcss-progressive-custom-properties': 5.0.0(postcss@8.5.10) + '@csstools/postcss-property-rule-prelude-list': 2.0.0(postcss@8.5.10) + '@csstools/postcss-random-function': 3.0.2(postcss@8.5.10) + '@csstools/postcss-relative-color-syntax': 4.0.3(postcss@8.5.10) + '@csstools/postcss-scope-pseudo-class': 5.0.0(postcss@8.5.10) + '@csstools/postcss-sign-functions': 2.0.2(postcss@8.5.10) + '@csstools/postcss-stepped-value-functions': 5.0.2(postcss@8.5.10) + '@csstools/postcss-syntax-descriptor-syntax-production': 2.0.0(postcss@8.5.10) + '@csstools/postcss-system-ui-font-family': 2.0.0(postcss@8.5.10) + '@csstools/postcss-text-decoration-shorthand': 5.0.3(postcss@8.5.10) + '@csstools/postcss-trigonometric-functions': 5.0.2(postcss@8.5.10) + '@csstools/postcss-unset-value': 5.0.0(postcss@8.5.10) + autoprefixer: 10.5.0(postcss@8.5.10) + browserslist: 4.28.2 + css-blank-pseudo: 8.0.1(postcss@8.5.10) + css-has-pseudo: 8.0.0(postcss@8.5.10) + css-prefers-color-scheme: 11.0.0(postcss@8.5.10) + cssdb: 8.8.0 + postcss: 8.5.10 + postcss-attribute-case-insensitive: 8.0.0(postcss@8.5.10) + postcss-clamp: 4.1.0(postcss@8.5.10) + postcss-color-functional-notation: 8.0.3(postcss@8.5.10) + postcss-color-hex-alpha: 11.0.0(postcss@8.5.10) + postcss-color-rebeccapurple: 11.0.0(postcss@8.5.10) + postcss-custom-media: 12.0.1(postcss@8.5.10) + postcss-custom-properties: 15.0.1(postcss@8.5.10) + postcss-custom-selectors: 9.0.1(postcss@8.5.10) + postcss-dir-pseudo-class: 10.0.0(postcss@8.5.10) + postcss-double-position-gradients: 7.0.0(postcss@8.5.10) + postcss-focus-visible: 11.0.0(postcss@8.5.10) + postcss-focus-within: 10.0.0(postcss@8.5.10) + postcss-font-variant: 5.0.0(postcss@8.5.10) + postcss-gap-properties: 7.0.0(postcss@8.5.10) + postcss-image-set-function: 8.0.0(postcss@8.5.10) + postcss-lab-function: 8.0.3(postcss@8.5.10) + postcss-logical: 9.0.0(postcss@8.5.10) + postcss-nesting: 14.0.0(postcss@8.5.10) + postcss-opacity-percentage: 3.0.0(postcss@8.5.10) + postcss-overflow-shorthand: 7.0.0(postcss@8.5.10) + postcss-page-break: 3.0.4(postcss@8.5.10) + postcss-place: 11.0.0(postcss@8.5.10) + postcss-pseudo-class-any-link: 11.0.0(postcss@8.5.10) + postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.10) + postcss-selector-not: 9.0.0(postcss@8.5.10) - postcss-pseudo-class-any-link@7.1.6(postcss@8.5.8): + postcss-pseudo-class-any-link@11.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 - postcss-reduce-initial@5.1.2(postcss@8.5.8): + postcss-reduce-initial@5.1.2(postcss@8.5.10): dependencies: browserslist: 4.25.2 caniuse-api: 3.0.0 - postcss: 8.5.8 + postcss: 8.5.10 - postcss-reduce-transforms@5.1.0(postcss@8.5.8): + postcss-reduce-transforms@5.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-value-parser: 4.2.0 - postcss-replace-overflow-wrap@4.0.0(postcss@8.5.8): + postcss-replace-overflow-wrap@4.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 - postcss-selector-not@6.0.1(postcss@8.5.8): + postcss-selector-not@9.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.8 - postcss-selector-parser: 6.1.2 + postcss: 8.5.10 + postcss-selector-parser: 7.1.1 postcss-selector-parser@6.1.2: dependencies: @@ -11055,15 +12145,20 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@5.1.0(postcss@8.5.8): + postcss-selector-parser@7.1.1: dependencies: - postcss: 8.5.8 + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@5.1.0(postcss@8.5.10): + dependencies: + postcss: 8.5.10 postcss-value-parser: 4.2.0 svgo: 2.8.0 - postcss-unique-selectors@5.1.1(postcss@8.5.8): + postcss-unique-selectors@5.1.1(postcss@8.5.10): dependencies: - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 postcss-value-parser@4.2.0: {} @@ -11074,7 +12169,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.8: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -11100,28 +12195,28 @@ snapshots: pretty-bytes@5.6.0: {} - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - pretty-format@30.0.5: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 react-is: 18.3.1 - prisma@7.6.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + pretty-format@30.3.0: dependencies: - '@prisma/config': 7.6.0 - '@prisma/dev': 0.24.3(typescript@5.9.3) - '@prisma/engines': 7.6.0 + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.3): + dependencies: + '@prisma/config': 7.7.0 + '@prisma/dev': 0.24.3(typescript@6.0.3) + '@prisma/engines': 7.7.0 '@prisma/studio-core': 0.27.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) mysql2: 3.15.3 postgres: 3.4.7 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -11154,7 +12249,7 @@ snapshots: proxy-from-env@1.0.0: {} - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -11163,7 +12258,9 @@ snapshots: pure-rand@7.0.1: {} - qs@6.14.0: + pure-rand@8.4.0: {} + + qs@6.14.2: dependencies: side-channel: 1.1.0 @@ -11171,13 +12268,9 @@ snapshots: raf-schd@4.0.3: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - rc9@2.1.2: dependencies: - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 react-aria-components@1.17.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): @@ -11210,9 +12303,8 @@ snapshots: react: 19.2.5 scheduler: 0.27.0 - react-error-boundary@4.1.2(react@19.2.5): + react-error-boundary@6.1.1(react@19.2.5): dependencies: - '@babel/runtime': 7.28.3 react: 19.2.5 react-hook-form@7.71.1(react@19.2.5): @@ -11227,17 +12319,17 @@ snapshots: dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.5 - use-sync-external-store: 1.5.0(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 redux: 5.0.1 - react-resizable-panels@4.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-resizable-panels@4.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - react-simple-maps@2.3.0(prop-types@15.8.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-simple-maps@3.0.0(prop-types@15.8.1)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: d3-geo: 2.0.2 d3-selection: 2.0.0 @@ -11263,10 +12355,8 @@ snapshots: optionalDependencies: react-dom: 19.2.5(react@19.2.5) - react-window@1.8.11(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-window@2.2.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - '@babel/runtime': 7.28.3 - memoize-one: 5.2.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -11294,14 +12384,16 @@ snapshots: readdirp@4.1.2: {} - redis@4.7.1: + redis@5.12.1: dependencies: - '@redis/bloom': 1.2.0(@redis/client@1.6.1) - '@redis/client': 1.6.1 - '@redis/graph': 1.1.1(@redis/client@1.6.1) - '@redis/json': 1.0.7(@redis/client@1.6.1) - '@redis/search': 1.2.0(@redis/client@1.6.1) - '@redis/time-series': 1.1.0(@redis/client@1.6.1) + '@redis/bloom': 5.12.1(@redis/client@5.12.1) + '@redis/client': 5.12.1 + '@redis/json': 5.12.1(@redis/client@5.12.1) + '@redis/search': 5.12.1(@redis/client@5.12.1) + '@redis/time-series': 5.12.1(@redis/client@5.12.1) + transitivePeerDependencies: + - '@node-rs/xxhash' + - '@opentelemetry/api' redux@5.0.1: {} @@ -11347,14 +12439,19 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve.exports@2.0.3: {} - resolve@1.22.10: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -11366,10 +12463,6 @@ snapshots: rfdc@1.4.1: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rollup-plugin-copy@3.5.0: dependencies: '@types/fs-extra': 8.1.5 @@ -11383,36 +12476,36 @@ snapshots: del: 8.0.1 rollup: 4.60.1 - rollup-plugin-dts@6.4.1(rollup@4.60.1)(typescript@5.9.3): + rollup-plugin-dts@6.4.1(rollup@4.60.1)(typescript@6.0.3): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 convert-source-map: 2.0.0 magic-string: 0.30.21 rollup: 4.60.1 - typescript: 5.9.3 + typescript: 6.0.3 optionalDependencies: '@babel/code-frame': 7.29.0 - rollup-plugin-node-externals@8.1.2(rollup@4.60.1): - dependencies: + rollup-plugin-node-externals@9.0.1(rollup@4.60.1): + optionalDependencies: rollup: 4.60.1 rollup-plugin-peer-deps-external@2.2.4(rollup@4.60.1): dependencies: rollup: 4.60.1 - rollup-plugin-postcss@4.0.2(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)): + rollup-plugin-postcss@4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)): dependencies: chalk: 4.1.2 concat-with-sourcemaps: 1.1.0 - cssnano: 5.1.15(postcss@8.5.8) + cssnano: 5.1.15(postcss@8.5.10) import-cwd: 3.0.0 p-queue: 6.6.2 pify: 5.0.0 - postcss: 8.5.8 - postcss-load-config: 3.1.4(postcss@8.5.8)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) - postcss-modules: 4.3.1(postcss@8.5.8) + postcss: 8.5.10 + postcss-load-config: 3.1.4(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) + postcss-modules: 4.3.1(postcss@8.5.10) promise.series: 0.2.0 resolve: 1.22.10 rollup-pluginutils: 2.8.2 @@ -11523,13 +12616,12 @@ snapshots: seq-queue@0.0.5: {} - serialize-error@12.0.0: + serialize-error@13.0.1: dependencies: - type-fest: 4.41.0 + non-error: 0.1.0 + type-fest: 5.6.0 - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + serialize-javascript@7.0.5: {} set-function-length@1.2.2: dependencies: @@ -11651,7 +12743,7 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - smob@1.5.0: {} + smob@1.6.1: {} snake-case@3.0.4: dependencies: @@ -11736,7 +12828,7 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 string.prototype.padend@3.1.6: dependencies: @@ -11776,7 +12868,7 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 @@ -11790,17 +12882,17 @@ snapshots: style-inject@0.3.0: {} - styled-jsx@5.1.6(@babel/core@7.28.3)(react@19.2.5): + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.5): dependencies: client-only: 0.0.1 react: 19.2.5 optionalDependencies: - '@babel/core': 7.28.3 + '@babel/core': 7.29.0 - stylehacks@5.1.1(postcss@8.5.8): + stylehacks@5.1.1(postcss@8.5.10): dependencies: browserslist: 4.25.2 - postcss: 8.5.8 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 sucrase@3.35.0: @@ -11849,6 +12941,14 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 + synckit@0.11.12: + dependencies: + '@pkgr/core': 0.2.9 + + systeminformation@5.31.5: {} + + tagged-tag@1.0.0: {} + tailwind-merge@3.4.0: {} tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18): @@ -11867,20 +12967,20 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 - terser@5.43.1: + terser@5.46.1: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 test-exclude@6.0.0: dependencies: - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 3.1.5 - thenby@1.3.4: {} + thenby@1.4.0: {} thenify-all@1.6.0: dependencies: @@ -11896,16 +12996,21 @@ snapshots: tiny-invariant@1.3.3: {} - tiny-lru@11.4.7: {} + tiny-lru@13.0.0: {} tinyexec@0.3.2: {} - tinyexec@1.0.4: {} + tinyexec@1.1.1: {} tinyglobby@0.2.14: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tldts-core@6.1.86: {} @@ -11933,66 +13038,68 @@ 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.27.4)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.28.0)(jest-util@30.3.0)(jest@30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)))(typescript@6.0.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.12.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3)) + handlebars: 4.7.9 + jest: 30.3.0(@types/node@25.6.0)(ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.7.4 type-fest: 4.41.0 - typescript: 5.9.3 + typescript: 6.0.3 yargs-parser: 21.1.1 optionalDependencies: - '@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.27.4 - jest-util: 30.0.5 + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + esbuild: 0.28.0 + jest-util: 30.3.0 - ts-morph@27.0.2: + ts-morph@28.0.0: dependencies: - '@ts-morph/common': 0.28.1 + '@ts-morph/common': 0.29.0 code-block-writer: 13.0.3 - ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.21))(@types/node@24.12.0)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.26(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@6.0.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.12.0 + '@types/node': 25.6.0 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.9.3 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.15.11(@swc/helpers@0.5.21) + '@swc/core': 1.15.26(@swc/helpers@0.5.21) + + tslib@1.14.1: {} tslib@2.8.1: {} - tsup@8.5.1(@swc/core@1.15.11(@swc/helpers@0.5.21))(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1): + tsup@8.5.1(@swc/core@1.15.26(@swc/helpers@0.5.21))(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.1): dependencies: - bundle-require: 5.1.0(esbuild@0.27.4) + bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.3(supports-color@8.1.1) - esbuild: 0.27.4 + esbuild: 0.27.7 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.60.1 source-map: 0.7.6 @@ -12001,9 +13108,9 @@ snapshots: tinyglobby: 0.2.14 tree-kill: 1.2.2 optionalDependencies: - '@swc/core': 1.15.11(@swc/helpers@0.5.21) - postcss: 8.5.8 - typescript: 5.9.3 + '@swc/core': 1.15.26(@swc/helpers@0.5.21) + postcss: 8.5.10 + typescript: 6.0.3 transitivePeerDependencies: - jiti - supports-color @@ -12012,7 +13119,7 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.4 + esbuild: 0.27.7 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -12027,8 +13134,14 @@ snapshots: type-fest@0.21.3: {} + type-fest@0.8.1: {} + type-fest@4.41.0: {} + type-fest@5.6.0: + dependencies: + tagged-tag: 1.0.0 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -12062,7 +13175,7 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript@5.9.3: {} + typescript@6.0.3: {} ua-is-frozen@0.1.2: {} @@ -12084,7 +13197,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.16.0: {} + undici-types@7.19.2: {} unicorn-magic@0.3.0: {} @@ -12092,6 +13205,30 @@ snapshots: universalify@2.0.1: {} + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + untildify@4.0.0: {} update-browserslist-db@1.1.3(browserslist@4.25.2): @@ -12100,20 +13237,18 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-intl@4.8.4(react@19.2.5): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - '@formatjs/fast-memoize': 3.1.1 + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-intl@4.9.1(react@19.2.5): + dependencies: + '@formatjs/fast-memoize': 3.1.2 '@schummar/icu-type-parser': 1.21.5 - icu-minify: 4.8.4 - intl-messageformat: 11.2.0 - react: 19.2.5 - - use-memo-one@1.1.3(react@19.2.5): - dependencies: - react: 19.2.5 - - use-sync-external-store@1.5.0(react@19.2.5): - dependencies: + icu-minify: 4.9.1 + intl-messageformat: 11.2.1 react: 19.2.5 use-sync-external-store@1.6.0(react@19.2.5): @@ -12130,13 +13265,13 @@ snapshots: v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - valibot@1.2.0(typescript@5.9.3): + valibot@1.2.0(typescript@6.0.3): optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 validate-npm-package-license@3.0.4: dependencies: @@ -12224,14 +13359,14 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} - write-file-atomic@4.0.2: + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - signal-exit: 3.0.7 + signal-exit: 4.1.0 xtend@4.0.2: {} @@ -12239,8 +13374,6 @@ snapshots: yallist@3.1.1: {} - yallist@4.0.0: {} - yallist@5.0.0: {} yaml@1.10.2: {} diff --git a/public/intl/country/en-GB.json b/public/intl/country/en-GB.json index 95a4e329a..77a95d973 100644 --- a/public/intl/country/en-GB.json +++ b/public/intl/country/en-GB.json @@ -227,7 +227,7 @@ "TO": "Tonga", "TT": "Trinidad & Tobago", "TN": "Tunisia", - "TR": "Turkey", + "TR": "T\u00fcrkiye", "TM": "Turkmenistan", "TC": "Turks & Caicos Islands", "TV": "Tuvalu", diff --git a/public/intl/country/en-US.json b/public/intl/country/en-US.json index 95a4e329a..77a95d973 100644 --- a/public/intl/country/en-US.json +++ b/public/intl/country/en-US.json @@ -227,7 +227,7 @@ "TO": "Tonga", "TT": "Trinidad & Tobago", "TN": "Tunisia", - "TR": "Turkey", + "TR": "T\u00fcrkiye", "TM": "Turkmenistan", "TC": "Turks & Caicos Islands", "TV": "Tuvalu", diff --git a/public/intl/messages/bs-BA.json b/public/intl/messages/bs-BA.json index 7a42b4e08..a11f610bd 100644 --- a/public/intl/messages/bs-BA.json +++ b/public/intl/messages/bs-BA.json @@ -20,10 +20,8 @@ "all-time": "Cijelo vrijeme", "analysis": "Analiza", "analytics": "Analitike", - "aov": "AOV", "application": "Aplikacija", "apply": "Primijeni", - "arpu": "ARPU", "attribution": "Atribucija", "attribution-description": "Pogledajte kako korisnici komuniciraju s vašim marketingom i šta dovodi do konverzija.", "audience": "Publika", @@ -33,6 +31,7 @@ "behavior": "Ponašanje", "block-selector": "Odabir bloka", "boards": "Ploče", + "board-type": "Vrsta ploče", "bounce-rate": "Stopa napuštanja", "breakdown": "Pregled po kategorijama", "browser": "Preglednik", @@ -55,6 +54,8 @@ "confirm": "Potvrdi", "confirm-password": "Potvrdi šifru", "contains": "Sadrži", + "regex-match": "Odgovara regularnom izrazu", + "regex-not-match": "Ne odgovara regularnom izrazu", "content": "Sadržaj", "continue": "Nastavi", "conversion": "Konverzija", @@ -131,8 +132,8 @@ "funnels": "Lijevci", "goal": "Cilj", "goals": "Ciljevi", - "goals-description": "Pratite svoje ciljeve za prikaze stranica i događaje.", "good": "Dobro", + "goals-description": "Pratite svoje ciljeve za prikaze stranica i događaje.", "greater-than": "Veće od", "greater-than-equals": "Veće od ili jednako", "grouped": "Grupisano", @@ -140,10 +141,10 @@ "hostname": "Naziv hosta", "hour": "Sat", "includes": "Uključuje", - "inp": "INP", "insight": "Uvid", "insights": "Uvidi", "insights-description": "Zaronite dublje u vaše podatke korištenjem segmenata i filtera", + "inp": "INP", "invalid-url": "Nevažeći URL", "is": "Jeste", "is-false": "Nije tačno", @@ -177,11 +178,11 @@ "manage": "Upravljaj", "manager": "Menadžer", "mask-level": "Nivo maske", + "max": "Maks", + "max-duration": "Maksimalno trajanje", "match": "Podudaranje", "match-all": "Sve", "match-any": "Bilo koje", - "max": "Maks", - "max-duration": "Maksimalno trajanje", "maximize": "Proširi", "medium": "Srednje", "member": "Član", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {zapis} other {zapisa}}", "ok": "U redu", "online": "Na mreži", + "open": "Miješano", "organic-search": "Organska pretraga", "organic-shopping": "Organska kupovina", "organic-social": "Organske društvene mreže", @@ -212,8 +214,8 @@ "page": "Stranica", "page-of": "Strana {current} od {total}", "page-views": "Pregleda stranica", - "pages": "Stranice", "pageTitle": "Naslov stranice", + "pages": "Stranice", "paid-ads": "Plaćeni oglasi", "paid-search": "Plaćena pretraga", "paid-shopping": "Plaćena kupovina", @@ -225,7 +227,6 @@ "performance": "Performanse", "pixel": "Piksel", "pixels": "Pikseli", - "play": "Reprodukuj", "poor": "Loše", "powered-by": "Omogućeno s {name}", "preferences": "Postavke", @@ -246,16 +247,16 @@ "referrers": "Preporučioci", "refresh": "Osvježi", "regenerate": "Regeneriši", - "regex-match": "Odgovara regularnom izrazu", - "regex-not-match": "Ne odgovara regularnom izrazu", "region": "Regija", "regions": "Regioni", "remaining": "Preostalo", "remove": "Ukloni", "remove-member": "Ukloni člana", + "play": "Reprodukuj", "replay": "Ponovna reprodukcija", - "replay-enabled": "Ponovna reprodukcija omogućena", "replay-id": "Replay ID", + "replay-code": "Kod ponavljanja sesije", + "replay-enabled": "Ponovna reprodukcija omogućena", "replays": "Ponovne reprodukcije", "reports": "Izvještaji", "required": "Obavezno", @@ -268,21 +269,24 @@ "revenue-description": "Pogledajte svoje prihode tokom vremena.", "role": "Rola", "run-query": "Pokreni query", - "sample-rate": "Stopa uzorkovanja", - "sample-size": "Veličina uzorka", "save": "Sačuvaj", "save-cohort": "Spremi kohortu", + "save-replay": "Sačuvaj ponavljanje", "save-segment": "Spremi segment", + "sample-rate": "Stopa uzorkovanja", + "sample-size": "Veličina uzorka", "screen": "Ekran", "screens": "Ekrani", "search": "Traži", "segment": "Segment", "segments": "Segmenti", "select": "Odaberi", - "select-component": "Odaberite komponentu", + "select-link": "Odaberi link", + "select-pixel": "Odaberi piksel", "select-date": "Odaberi datum", "select-filter": "Odaberi filter", "select-role": "Odaberi rolu", + "select-component": "Odaberite komponentu", "select-website": "Odaberi web stranicu", "session": "Sesija", "session-data": "Podaci o sesiji", @@ -337,9 +341,15 @@ "unique": "Jedinstveno", "unique-events": "Jedinstveni događaji", "unique-visitors": "Jedinstvenih posjetitelja", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Jedinstveni kupci", + "customers": "Kupci", + "orders": "Narudžbe", + "saved": "Sačuvano", "unknown": "Nepoznato", "untitled": "Bezimeno", + "upgrade": "Nadogradi", "update": "Ažuriraj", "url": "URL", "user": "Korisnik", @@ -379,8 +389,8 @@ "confirm-reset": "Jeste li sigurni da želite resetovati {target}?", "delete-team-warning": "Brisanje tima će također obrisati sve web stranice tima.", "delete-website-warning": "Svi podaci web stranice biće obrisani.", - "empty-dashboard": "Vaša kontrolna tabla je prazna. Kliknite Uredi da dodate prvu komponentu.", "error": "Nešto je pošlo po zlu.", + "empty-dashboard": "Vaša kontrolna tabla je prazna. Kliknite Uredi da dodate prvu komponentu.", "event-log": "{event} na {url}", "forbidden": "Zabranjeno", "go-to-settings": "Idi na postavke", @@ -402,6 +412,7 @@ "reset-website": "Da resetujete ovu web stranicu, upišite {confirmation} dole da potvrdite.", "reset-website-warning": "Sve statistike o ovoj web stranici će biti obrisane, ali vaše postavke neće biti dirane.", "saved": "Sačuvano.", + "select-board-entity-first": "Prvo odaberite web-stranicu, piksel ili link.", "select-component-preview": "Odaberite komponentu za pregled", "select-website-first": "Prvo odaberite web stranicu", "sever-error": "Greška servera", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizirano", "user-deleted": "Korisnik obrisan.", "viewed-page": "Pogledana stranica", + "upgrade-required": "Ova funkcija zahtijeva pretplatu na plan {plan}.", "visitor-log": "Posjetitelj iz {country} koristi {browser} na {os} {device}" } } diff --git a/public/intl/messages/ca-ES.json b/public/intl/messages/ca-ES.json index 1adc4743b..0a804c0e1 100644 --- a/public/intl/messages/ca-ES.json +++ b/public/intl/messages/ca-ES.json @@ -20,10 +20,8 @@ "all-time": "Sempre", "analysis": "Anàlisi", "analytics": "Analítiques", - "aov": "AOV", "application": "Aplicació", "apply": "Aplica", - "arpu": "ARPU", "attribution": "Atribució", "attribution-description": "Vegeu com els usuaris interactuen amb el vostre màrqueting i què impulsa les conversions.", "audience": "Audiència", @@ -33,6 +31,7 @@ "behavior": "Comportament", "block-selector": "Selector de bloc", "boards": "Taulers", + "board-type": "Tipus de tauler", "bounce-rate": "Percentatge de rebot", "breakdown": "Desglossament", "browser": "Navegador", @@ -55,6 +54,8 @@ "confirm": "Confirmar", "confirm-password": "Confirma la contrasenya", "contains": "Conté", + "regex-match": "Coincideix amb l'expressió regular", + "regex-not-match": "No coincideix amb l'expressió regular", "content": "Contingut", "continue": "Continuar", "conversion": "Conversió", @@ -131,8 +132,8 @@ "funnels": "Embuts", "goal": "Meta", "goals": "Metes", - "goals-description": "Feu un seguiment de les seves metes per a pàgines vistes i esdeveniments.", "good": "Bo", + "goals-description": "Feu un seguiment de les seves metes per a pàgines vistes i esdeveniments.", "greater-than": "Més gran que", "greater-than-equals": "Més gran que o igual a", "grouped": "Agrupat", @@ -140,10 +141,10 @@ "hostname": "Nom de host", "hour": "Hora", "includes": "Inclou", - "inp": "INP", "insight": "Visió", "insights": "Insights", "insights-description": "Aprofundeixi en les seves dades mitjançant l'ús de segments i filtres.", + "inp": "INP", "invalid-url": "URL no vàlida", "is": "És igual a", "is-false": "És fals", @@ -177,11 +178,11 @@ "manage": "Administrar", "manager": "Responsable", "mask-level": "Nivell de màscara", + "max": "Màx", + "max-duration": "Durada màxima", "match": "Coincidència", "match-all": "Tots", "match-any": "Qualsevol", - "max": "Màx", - "max-duration": "Durada màxima", "maximize": "Expandeix", "medium": "Mitjà", "member": "Membre", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {registre} other {registres}}", "ok": "D'acord", "online": "En línia", + "open": "Mixt", "organic-search": "Cerca orgànica", "organic-shopping": "Compra orgànica", "organic-social": "Social orgànic", @@ -212,8 +214,8 @@ "page": "Pàgina", "page-of": "Pàgina {current} de {total}", "page-views": "Pàgines vistes", - "pages": "Pàgines", "pageTitle": "Títol de la pàgina", + "pages": "Pàgines", "paid-ads": "Anuncis de pagament", "paid-search": "Cerca de pagament", "paid-shopping": "Compra de pagament", @@ -225,7 +227,6 @@ "performance": "Rendiment", "pixel": "Píxel", "pixels": "Píxels", - "play": "Reprodueix", "poor": "Deficient", "powered-by": "Funciona amb {name}", "preferences": "Preferències", @@ -246,16 +247,16 @@ "referrers": "Referents", "refresh": "Refresca", "regenerate": "Regenerar", - "regex-match": "Coincideix amb l'expressió regular", - "regex-not-match": "No coincideix amb l'expressió regular", "region": "Regió", "regions": "Regions", "remaining": "Restant", "remove": "Treure", "remove-member": "Eliminar membre", + "play": "Reprodueix", "replay": "Repetició", - "replay-enabled": "Repetició activada", "replay-id": "Replay ID", + "replay-code": "Codi de repetició de sessió", + "replay-enabled": "Repetició activada", "replays": "Repeticions", "reports": "Informes", "required": "Obligatori", @@ -268,21 +269,24 @@ "revenue-description": "Observi els seus ingressos al llarg del temps.", "role": "Rol", "run-query": "Executar consulta", - "sample-rate": "Taxa de mostreig", - "sample-size": "Mida de la mostra", "save": "Desa", "save-cohort": "Desar cohort", + "save-replay": "Desa la repetició", "save-segment": "Desar segment", + "sample-rate": "Taxa de mostreig", + "sample-size": "Mida de la mostra", "screen": "Pantalla", "screens": "Pantalles", "search": "Buscar", "segment": "Segment", "segments": "Segments", "select": "Seleccionar", - "select-component": "Selecciona un component", + "select-link": "Selecciona l'enllaç", + "select-pixel": "Selecciona el píxel", "select-date": "Seleccionar data", "select-filter": "Seleccionar filtre", "select-role": "Seleccionar rol", + "select-component": "Selecciona un component", "select-website": "Seleccionar lloc web", "session": "Sessió", "session-data": "Dades de sessió", @@ -337,9 +341,15 @@ "unique": "Únic", "unique-events": "Esdeveniments únics", "unique-visitors": "Visitants únics", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clients Únics", + "customers": "Clients", + "orders": "Comandes", + "saved": "Desat", "unknown": "Desconegut", "untitled": "Sense títol", + "upgrade": "Actualitza", "update": "Actualitzar", "url": "URL", "user": "Usuari", @@ -379,8 +389,8 @@ "confirm-reset": "Segur que vol restablir les estadístiques de {target}?", "delete-team-warning": "Al eliminar un equip també s'eliminaran tots els llocs web de l'equip.", "delete-website-warning": "També s'esborraran totes les dades relacionades.", - "empty-dashboard": "El teu tauler és buit. Fes clic a Edita per afegir el teu primer component.", "error": "S'ha produït un error.", + "empty-dashboard": "El teu tauler és buit. Fes clic a Edita per afegir el teu primer component.", "event-log": "{event} a {url}", "forbidden": "Prohibit", "go-to-settings": "Vés a la configuració", @@ -402,6 +412,7 @@ "reset-website": "Per restablir aquest lloc web, escrigui {confirmation} al cuadre inferior per confirmar.", "reset-website-warning": "S'esborraran totes les estadístiques per aquest lloc web, però el codi de seguiment es mantindrà.", "saved": "S'ha desat amb èxit.", + "select-board-entity-first": "Selecciona primer un lloc web, píxel o enllaç.", "select-component-preview": "Selecciona un component per previsualitzar", "select-website-first": "Primer selecciona un lloc web", "sever-error": "Error del servidor", @@ -417,6 +428,7 @@ "unauthorized": "No autoritzat", "user-deleted": "Usuari eliminat.", "viewed-page": "Pàgina vista", + "upgrade-required": "Aquesta funció requereix una subscripció al pla {plan}.", "visitor-log": "Visitant de {country} usant {browser} a {os} {device}" } } diff --git a/public/intl/messages/cs-CZ.json b/public/intl/messages/cs-CZ.json index 3b64dd8fc..764dfd2ac 100644 --- a/public/intl/messages/cs-CZ.json +++ b/public/intl/messages/cs-CZ.json @@ -20,10 +20,8 @@ "all-time": "Celá doba", "analysis": "Analýza", "analytics": "Analytika", - "aov": "AOV", "application": "Aplikace", "apply": "Použít", - "arpu": "ARPU", "attribution": "Atribuce", "attribution-description": "Podívejte se, jak uživatelé interagují s vaším marketingem a co vede ke konverzím.", "audience": "Publikum", @@ -33,6 +31,7 @@ "behavior": "Chování", "block-selector": "Výběr bloku", "boards": "Nástěnky", + "board-type": "Typ nástěnky", "bounce-rate": "Okamžité opuštění", "breakdown": "Rozpis", "browser": "Prohlížeč", @@ -55,6 +54,8 @@ "confirm": "Potvrdit", "confirm-password": "Potvrdit heslo", "contains": "Obsahuje", + "regex-match": "Odpovídá regulárnímu výrazu", + "regex-not-match": "Neodpovídá regulárnímu výrazu", "content": "Obsah", "continue": "Pokračovat", "conversion": "Konverze", @@ -131,8 +132,8 @@ "funnels": "Trychtýře", "goal": "Cíl", "goals": "Cíle", - "goals-description": "Sledujte své cíle pro zobrazení stránek a události.", "good": "Dobré", + "goals-description": "Sledujte své cíle pro zobrazení stránek a události.", "greater-than": "Větší než", "greater-than-equals": "Větší nebo rovno", "grouped": "Seskupeno", @@ -140,10 +141,10 @@ "hostname": "Název hostitele", "hour": "Hodina", "includes": "Zahrnuje", - "inp": "INP", "insight": "Pohled", "insights": "Pohledy", "insights-description": "Ponořte se hlouběji do svých dat pomocí segmentů a filtrů.", + "inp": "INP", "invalid-url": "Neplatná URL", "is": "Je", "is-false": "Nepravda", @@ -177,11 +178,11 @@ "manage": "Spravovat", "manager": "Správce", "mask-level": "Úroveň masky", + "max": "Max", + "max-duration": "Maximální trvání", "match": "Shoda", "match-all": "Vše", "match-any": "Jakýkoli", - "max": "Max", - "max-duration": "Maximální trvání", "maximize": "Rozbalit", "medium": "Střední", "member": "Člen", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {záznam} other {záznamů}}", "ok": "OK", "online": "Online", + "open": "Smíšený", "organic-search": "Organické vyhledávání", "organic-shopping": "Organický nákup", "organic-social": "Organická sociální síť", @@ -212,8 +214,8 @@ "page": "Stránka", "page-of": "Stránka {current} z {total}", "page-views": "Zobrazení stránek", - "pages": "Stránky", "pageTitle": "Název stránky", + "pages": "Stránky", "paid-ads": "Placené reklamy", "paid-search": "Placené vyhledávání", "paid-shopping": "Placený nákup", @@ -225,7 +227,6 @@ "performance": "Výkon", "pixel": "Pixel", "pixels": "Pixely", - "play": "Přehrát", "poor": "Špatné", "powered-by": "Běží na {name}", "preferences": "Předvolby", @@ -246,16 +247,16 @@ "referrers": "Odkazující", "refresh": "Obnovit", "regenerate": "Regenerovat", - "regex-match": "Odpovídá regulárnímu výrazu", - "regex-not-match": "Neodpovídá regulárnímu výrazu", "region": "Region", "regions": "Regiony", "remaining": "Zbývá", "remove": "Odstranit", "remove-member": "Odstranit člena", + "play": "Přehrát", "replay": "Přehrávání", - "replay-enabled": "Přehrávání povoleno", "replay-id": "Replay ID", + "replay-code": "Kód přehrání relace", + "replay-enabled": "Přehrávání povoleno", "replays": "Přehrávání", "reports": "Hlášení", "required": "Povinné", @@ -268,21 +269,24 @@ "revenue-description": "Podívejte se na své příjmy v průběhu času.", "role": "Role", "run-query": "Spustit dotaz", - "sample-rate": "Frekvence vzorkování", - "sample-size": "Velikost vzorku", "save": "Uložit", "save-cohort": "Uložit kohortu", + "save-replay": "Uložit přehrání", "save-segment": "Uložit segment", + "sample-rate": "Frekvence vzorkování", + "sample-size": "Velikost vzorku", "screen": "Obrazovka", "screens": "Obrazovky", "search": "Hledat", "segment": "Segment", "segments": "Segmenty", "select": "Vybrat", - "select-component": "Vyberte komponentu", + "select-link": "Vybrat odkaz", + "select-pixel": "Vybrat pixel", "select-date": "Vybrat datum", "select-filter": "Vybrat filtr", "select-role": "Vybrat roli", + "select-component": "Vyberte komponentu", "select-website": "Vybrat web", "session": "Relace", "session-data": "Data relace", @@ -337,9 +341,15 @@ "unique": "Unikátní", "unique-events": "Unikátní události", "unique-visitors": "Jedinečné návštěvy", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unikátní zákazníci", + "customers": "Zákazníci", + "orders": "Objednávky", + "saved": "Uloženo", "unknown": "Neznámý", "untitled": "Bez názvu", + "upgrade": "Upgradovat", "update": "Aktualizovat", "url": "URL", "user": "Uživatel", @@ -379,8 +389,8 @@ "confirm-reset": "Are your sure you want to reset {target}'s statistics?", "delete-team-warning": "Smazání týmu smaže také všechny weby týmu.", "delete-website-warning": "Všechna související data budou také smazána.", - "empty-dashboard": "Váš řídicí panel je prázdný. Klikněte na Upravit a přidejte první komponentu.", "error": "Něco se pokazilo.", + "empty-dashboard": "Váš řídicí panel je prázdný. Klikněte na Upravit a přidejte první komponentu.", "event-log": "{event} na {url}", "forbidden": "Zakázáno", "go-to-settings": "Jít do nastavení", @@ -402,6 +412,7 @@ "reset-website": "Pro resetování tohoto webu zadejte {confirmation} do pole níže.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Úspěšně uloženo.", + "select-board-entity-first": "Nejprve vyberte web, pixel nebo odkaz.", "select-component-preview": "Vyberte komponentu pro náhled", "select-website-first": "Nejprve vyberte web", "sever-error": "Chyba serveru", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizováno", "user-deleted": "Uživatel smazán.", "viewed-page": "Zobrazená stránka", + "upgrade-required": "Tato funkce vyžaduje předplatné plánu {plan}.", "visitor-log": "Návštěvník z {country} s prohlížečem {browser} na {os} {device}" } } diff --git a/public/intl/messages/da-DK.json b/public/intl/messages/da-DK.json index 967d9a0cf..2f005c7f6 100644 --- a/public/intl/messages/da-DK.json +++ b/public/intl/messages/da-DK.json @@ -20,10 +20,8 @@ "all-time": "Altid", "analysis": "Analyse", "analytics": "Analyser", - "aov": "AOV", "application": "Applikation", "apply": "Anvend", - "arpu": "ARPU", "attribution": "Attribuering", "attribution-description": "Se, hvordan brugere interagerer med din markedsføring, og hvad der driver konverteringer.", "audience": "Målgruppe", @@ -33,6 +31,7 @@ "behavior": "Adfærd", "block-selector": "Blokvælger", "boards": "Tavler", + "board-type": "Tavletype", "bounce-rate": "Afvisningsprocent", "breakdown": "Opdeling", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Bekræft", "confirm-password": "Godkendt adgangskode", "contains": "Indeholder", + "regex-match": "Matcher regulært udtryk", + "regex-not-match": "Matcher ikke regulært udtryk", "content": "Indhold", "continue": "Fortsæt", "conversion": "Konvertering", @@ -131,8 +132,8 @@ "funnels": "Tragte", "goal": "Mål", "goals": "Mål", - "goals-description": "Følg dine mål for sidevisninger og hændelser.", "good": "God", + "goals-description": "Følg dine mål for sidevisninger og hændelser.", "greater-than": "Større end", "greater-than-equals": "Større end eller lig med", "grouped": "Gruperet", @@ -140,10 +141,10 @@ "hostname": "Værtsnavn", "hour": "Time", "includes": "Inkluderer", - "inp": "INP", "insight": "Indsigt", "insights": "Indsigter", "insights-description": "Dyk dybere ned i dine data ved at bruge segmenter og filtre.", + "inp": "INP", "invalid-url": "Ugyldig URL", "is": "Er", "is-false": "Er falsk", @@ -177,11 +178,11 @@ "manage": "Administrer", "manager": "Leder", "mask-level": "Maskeniveau", + "max": "Maks", + "max-duration": "Maksimal varighed", "match": "Match", "match-all": "Alle", "match-any": "Enhver", - "max": "Maks", - "max-duration": "Maksimal varighed", "maximize": "Udvid", "medium": "Medie", "member": "Medlem", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {post} other {poster}}", "ok": "OK", "online": "Online", + "open": "Blandet", "organic-search": "Organisk søgning", "organic-shopping": "Organisk shopping", "organic-social": "Organisk social", @@ -212,8 +214,8 @@ "page": "Side", "page-of": "Side {current} af {total}", "page-views": "Sidevisninger", - "pages": "Sider", "pageTitle": "Sidetitel", + "pages": "Sider", "paid-ads": "Betalte annoncer", "paid-search": "Betalt søgning", "paid-shopping": "Betalt shopping", @@ -225,7 +227,6 @@ "performance": "Ydeevne", "pixel": "Pixel", "pixels": "Pixels", - "play": "Afspil", "poor": "Dårlig", "powered-by": "Drevet af {name}", "preferences": "Præferencer", @@ -246,16 +247,16 @@ "referrers": "Henvisninger", "refresh": "Opdater", "regenerate": "Gendan", - "regex-match": "Matcher regulært udtryk", - "regex-not-match": "Matcher ikke regulært udtryk", "region": "Region", "regions": "Regioner", "remaining": "Tilbageværende", "remove": "Fjern", "remove-member": "Fjern medlem", + "play": "Afspil", "replay": "Afspilning", - "replay-enabled": "Afspilning aktiveret", "replay-id": "Replay ID", + "replay-code": "Kode til sessionsgengivelse", + "replay-enabled": "Afspilning aktiveret", "replays": "Afspilninger", "reports": "Rapporter", "required": "Påkrævet", @@ -268,21 +269,24 @@ "revenue-description": "Se din indtægt over tid.", "role": "Rolle", "run-query": "Kør forespørgsel", - "sample-rate": "Samplingshastighed", - "sample-size": "Stikprøvestørrelse", "save": "Gem", "save-cohort": "Gem kohorte", + "save-replay": "Gem gengivelse", "save-segment": "Gem segment", + "sample-rate": "Samplingshastighed", + "sample-size": "Stikprøvestørrelse", "screen": "Skærm", "screens": "Skærme", "search": "Søg", "segment": "Segment", "segments": "Segmenter", "select": "Vælg", - "select-component": "Vælg komponent", + "select-link": "Vælg link", + "select-pixel": "Vælg pixel", "select-date": "Vælg dato", "select-filter": "Vælg filter", "select-role": "Vælg rolle", + "select-component": "Vælg komponent", "select-website": "Vælg hjemmeside", "session": "Session", "session-data": "Sessionsdata", @@ -337,9 +341,15 @@ "unique": "Unik", "unique-events": "Unikke begivenheder", "unique-visitors": "Unikke besøgende", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unikke kunder", + "customers": "Kunder", + "orders": "Ordrer", + "saved": "Gemt", "unknown": "Ukendt", "untitled": "Uden titel", + "upgrade": "Opgrader", "update": "Opdater", "url": "URL", "user": "Bruger", @@ -379,8 +389,8 @@ "confirm-reset": "Er du sikker på at du ville nulstille {target}'s statistikker?", "delete-team-warning": "Sletning af et hold sletter også alle holdets websites.", "delete-website-warning": "Alle tilknyttede data slettes også.", - "empty-dashboard": "Dit dashboard er tomt. Klik på Rediger for at tilføje din første komponent.", "error": "Noget gik galt.", + "empty-dashboard": "Dit dashboard er tomt. Klik på Rediger for at tilføje din første komponent.", "event-log": "{event}{url}", "forbidden": "Forbudt", "go-to-settings": "Gå til betjeningspanel", @@ -402,6 +412,7 @@ "reset-website": "For at nulstille denne website, skriv {confirmation} i feltet herunder for at bekræfte.", "reset-website-warning": "Alle statistikker for denne hjemmeside ville blive slettet, men sporingskode ville forblive intakt.", "saved": "Gemt!", + "select-board-entity-first": "Vælg først et website, pixel eller link.", "select-component-preview": "Vælg en komponent for at se forhåndsvisning", "select-website-first": "Vælg et websted først", "sever-error": "Serverfejl", @@ -417,6 +428,7 @@ "unauthorized": "Ikke autoriseret", "user-deleted": "Bruger slettet.", "viewed-page": "Vist side", + "upgrade-required": "Denne funktion kræver et {plan}-abonnement.", "visitor-log": "Besøgende fra {country} bruger {browser}{os} {device}" } } diff --git a/public/intl/messages/de-CH.json b/public/intl/messages/de-CH.json index fecef5cc1..50fedf16c 100644 --- a/public/intl/messages/de-CH.json +++ b/public/intl/messages/de-CH.json @@ -20,10 +20,8 @@ "all-time": "Gsamte Zitruum", "analysis": "Analyse", "analytics": "Analytik", - "aov": "AOV", "application": "Anwendung", "apply": "Aawände", - "arpu": "ARPU", "attribution": "Zuordnig", "attribution-description": "Lueg wie d'Benutzer mit dim Marketing interagiere und was zu Umwandlige führt.", "audience": "Zielgruppe", @@ -33,6 +31,7 @@ "behavior": "Verhalte", "block-selector": "Blockauswahl", "boards": "Boards", + "board-type": "Board-Typ", "bounce-rate": "Absprungsrate", "breakdown": "Uufschlüsselig", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Bestätige", "confirm-password": "Passwort widerhole", "contains": "Enthaltet", + "regex-match": "Entspricht regulärem Ausdruck", + "regex-not-match": "Entspricht nicht regulärem Ausdruck", "content": "Inhalt", "continue": "Wiiter", "conversion": "Umwandlig", @@ -131,8 +132,8 @@ "funnels": "Trichter", "goal": "Ziel", "goals": "Ziele", - "goals-description": "verfolged Sie Ihri Ziel für Siitenufrüef und Ereigniss.", "good": "Gut", + "goals-description": "verfolged Sie Ihri Ziel für Siitenufrüef und Ereigniss.", "greater-than": "Grösser als", "greater-than-equals": "Grösser oder gliich", "grouped": "Gruppiert", @@ -140,10 +141,10 @@ "hostname": "Hostnam", "hour": "Stunde", "includes": "Isch debii", - "inp": "INP", "insight": "Iiblick", "insights": "Iiblick", "insights-description": "Vertüfed Sie sich i Ihri Date, mit Hilf vo Segment und Filter.", + "inp": "INP", "invalid-url": "Ungültige URL", "is": "Isch", "is-false": "Isch falsch", @@ -177,11 +178,11 @@ "manage": "Verwalte", "manager": "Verwalter", "mask-level": "Maskierungsstufe", + "max": "Max", + "max-duration": "Maximale Dauer", "match": "Übereinstimmung", "match-all": "Alle", "match-any": "Beliebige", - "max": "Max", - "max-duration": "Maximale Dauer", "maximize": "Uusklappe", "medium": "Medium", "member": "Mitglied", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {Datensatz} other {Datensätze}}", "ok": "OK", "online": "Online", + "open": "Gemischt", "organic-search": "Organischi Suechi", "organic-shopping": "Organischi Iikauf", "organic-social": "Organischi Social Media", @@ -212,8 +214,8 @@ "page": "Siite", "page-of": "Siite {current} vo {total}", "page-views": "Siitenufrüef", - "pages": "Siite", "pageTitle": "Siitetitel", + "pages": "Siite", "paid-ads": "Bezahlti Werbung", "paid-search": "Bezahlti Suechi", "paid-shopping": "Bezahlti Iikauf", @@ -225,7 +227,6 @@ "performance": "Leistung", "pixel": "Pixel", "pixels": "Pixel", - "play": "Abspielen", "poor": "Schlecht", "powered-by": "Betriibe dur {name}", "preferences": "Einstellungen", @@ -246,16 +247,16 @@ "referrers": "Verwiisendi", "refresh": "Aktualisiere", "regenerate": "Erneuere", - "regex-match": "Entspricht regulärem Ausdruck", - "regex-not-match": "Entspricht nicht regulärem Ausdruck", "region": "Region", "regions": "Regionä", "remaining": "Verblibe", "remove": "Entferne", "remove-member": "Mitglied entferne", + "play": "Abspielen", "replay": "Wiedergabe", - "replay-enabled": "Wiedergabe aktiviert", "replay-id": "Replay ID", + "replay-code": "Session-Replay-Code", + "replay-enabled": "Wiedergabe aktiviert", "replays": "Wiedergaben", "reports": "Brichte", "required": "Erforderlich", @@ -268,21 +269,24 @@ "revenue-description": "Lueged Sie sich Ihre Umsatz im Lauf vor Ziit a.", "role": "Rollä", "run-query": "Abfrag starte", - "sample-rate": "Abtastrate", - "sample-size": "Stichprobengrösse", "save": "Speichere", "save-cohort": "Kohorte speichern", + "save-replay": "Replay speichern", "save-segment": "Segment speichern", + "sample-rate": "Abtastrate", + "sample-size": "Stichprobengrösse", "screen": "Bildschirm", "screens": "Bildschirmuflösige", "search": "Sueche", "segment": "Segment", "segments": "Segmente", "select": "Auswähle", - "select-component": "Komponente auswählen", + "select-link": "Link auswählen", + "select-pixel": "Pixel auswählen", "select-date": "Datä uuswähle", "select-filter": "Filter uuswähle", "select-role": "Rollä uuswähle", + "select-component": "Komponente auswählen", "select-website": "Websiite uuswähle", "session": "Sitzig", "session-data": "Sitzigsdate", @@ -337,9 +341,15 @@ "unique": "Einzigartigi", "unique-events": "Einzigartige Ereignisse", "unique-visitors": "Einzigartigi Bsuecher", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Einzigartigi Kunde", + "customers": "Kunden", + "orders": "Bestellungen", + "saved": "Gespeichert", "unknown": "Unbekannt", "untitled": "Unbennant", + "upgrade": "Upgrade", "update": "Aktualisieren", "url": "URL", "user": "Benutzer", @@ -379,8 +389,8 @@ "confirm-reset": "Sind Sie sicher, dass Sie d Statistike vo {target} zruggsetze wänd?", "delete-team-warning": "Es Team lösche dued ebefalls alli team Websiite lösche.", "delete-website-warning": "Alli dezueghörige Date werded ebefalls glöscht.", - "empty-dashboard": "Ihr Dashboard ist leer. Klicken Sie auf Bearbeiten, um Ihre erste Komponente hinzuzufügen.", "error": "Es isch en Fehler ufträte.", + "empty-dashboard": "Ihr Dashboard ist leer. Klicken Sie auf Bearbeiten, um Ihre erste Komponente hinzuzufügen.", "event-log": "{event} uf {url}", "forbidden": "Verboten", "go-to-settings": "Zu de Istellige", @@ -402,6 +412,7 @@ "reset-website": "Um die Websiite zruggzsetze, typed Sie {confirmation} is Feld unde dran.", "reset-website-warning": "Alli Date für die Websiite werdet glöscht, nur de Tracking Code blibt bestah.", "saved": "Erfolgrich gspeichert.", + "select-board-entity-first": "Wählen Sie zuerst eine Website, einen Pixel oder einen Link aus.", "select-component-preview": "Wählen Sie eine Komponente für die Vorschau", "select-website-first": "Wählen Sie zuerst eine Website", "sever-error": "Serverfehler", @@ -417,6 +428,7 @@ "unauthorized": "Nicht autorisiert", "user-deleted": "Bnutzer glöscht.", "viewed-page": "Siite agluegt", + "upgrade-required": "Diese Funktion erfordert ein {plan}-Abonnement.", "visitor-log": "Bsuecher us {country} nutzt {browser} uf {os} {device}" } } diff --git a/public/intl/messages/de-DE.json b/public/intl/messages/de-DE.json index e5be06cb9..cb422375a 100644 --- a/public/intl/messages/de-DE.json +++ b/public/intl/messages/de-DE.json @@ -20,10 +20,8 @@ "all-time": "Gesamter Zeitraum", "analysis": "Analyse", "analytics": "Analysen", - "aov": "AOV", "application": "Anwendung", "apply": "Anwenden", - "arpu": "ARPU", "attribution": "Zuordnung", "attribution-description": "Sehen Sie, wie Nutzer mit Ihrem Marketing interagieren und was zu Konversionen führt.", "audience": "Zielgruppe", @@ -33,6 +31,7 @@ "behavior": "Verhalten", "block-selector": "Blockauswahl", "boards": "Boards", + "board-type": "Board-Typ", "bounce-rate": "Absprungrate", "breakdown": "Aufschlüsselung", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Bestätigen", "confirm-password": "Passwort wiederholen", "contains": "Enthält", + "regex-match": "Entspricht regulärem Ausdruck", + "regex-not-match": "Entspricht nicht regulärem Ausdruck", "content": "Inhalt", "continue": "Weiter", "conversion": "Konversion", @@ -131,8 +132,8 @@ "funnels": "Trichter", "goal": "Ziel", "goals": "Ziele", - "goals-description": "Verfolgen Sie Ihre Ziele für Seitenaufrufe und Ereignisse.", "good": "Gut", + "goals-description": "Verfolgen Sie Ihre Ziele für Seitenaufrufe und Ereignisse.", "greater-than": "Größer als", "greater-than-equals": "Größer oder gleich", "grouped": "Gruppiert", @@ -140,10 +141,10 @@ "hostname": "Hostname", "hour": "Stunde", "includes": "Enthält", - "inp": "INP", "insight": "Einblick", "insights": "Einblicke", "insights-description": "Vertiefen Sie sich mit Hilfe von Segmenten und Filtern in Ihre Daten.", + "inp": "INP", "invalid-url": "Ungültige URL", "is": "Ist", "is-false": "Ist falsch", @@ -177,11 +178,11 @@ "manage": "Verwalten", "manager": "Verwaltung", "mask-level": "Maskierungsstufe", + "max": "Max", + "max-duration": "Maximale Dauer", "match": "Übereinstimmung", "match-all": "Alle", "match-any": "Beliebige", - "max": "Max", - "max-duration": "Maximale Dauer", "maximize": "Erweitern", "medium": "Medium", "member": "Mitglied", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {Datensatz} other {Datensätze}}", "ok": "OK", "online": "Online", + "open": "Gemischt", "organic-search": "Organische Suche", "organic-shopping": "Organisches Shopping", "organic-social": "Organisches Social Media", @@ -212,8 +214,8 @@ "page": "Seite", "page-of": "Seite {current} von {total}", "page-views": "Seitenaufrufe", - "pages": "Seiten", "pageTitle": "Seitentitel", + "pages": "Seiten", "paid-ads": "Bezahlte Anzeigen", "paid-search": "Bezahlte Suche", "paid-shopping": "Bezahltes Shopping", @@ -225,7 +227,6 @@ "performance": "Leistung", "pixel": "Pixel", "pixels": "Pixel", - "play": "Abspielen", "poor": "Schlecht", "powered-by": "Betrieben durch {name}", "preferences": "Einstellungen", @@ -246,16 +247,16 @@ "referrers": "Übermittler", "refresh": "Aktualisieren", "regenerate": "Erneuern", - "regex-match": "Entspricht regulärem Ausdruck", - "regex-not-match": "Entspricht nicht regulärem Ausdruck", "region": "Region", "regions": "Regionen", "remaining": "Verbleibend", "remove": "Entfernen", "remove-member": "Mitglied entfernen", + "play": "Abspielen", "replay": "Wiedergabe", - "replay-enabled": "Wiedergabe aktiviert", "replay-id": "Replay ID", + "replay-code": "Session-Replay-Code", + "replay-enabled": "Wiedergabe aktiviert", "replays": "Wiedergaben", "reports": "Berichte", "required": "Erforderlich", @@ -268,21 +269,24 @@ "revenue-description": "Haben Sie einen Blick auf Ihre Umsätze im Laufe der Zeit.", "role": "Rolle", "run-query": "Abfrage starten", - "sample-rate": "Abtastrate", - "sample-size": "Stichprobengröße", "save": "Speichern", "save-cohort": "Kohorte speichern", + "save-replay": "Replay speichern", "save-segment": "Segment speichern", + "sample-rate": "Abtastrate", + "sample-size": "Stichprobengröße", "screen": "Bildschirm", "screens": "Bildschirmauflösungen", "search": "Suche", "segment": "Segment", "segments": "Segmente", "select": "Auswählen", - "select-component": "Komponente auswählen", + "select-link": "Link auswählen", + "select-pixel": "Pixel auswählen", "select-date": "Datum auswählen", "select-filter": "Filter auswählen", "select-role": "Rolle auswählen", + "select-component": "Komponente auswählen", "select-website": "Website auswählen", "session": "Sitzung", "session-data": "Sitzungsdaten", @@ -337,9 +341,15 @@ "unique": "Einzigartig", "unique-events": "Einzigartige Ereignisse", "unique-visitors": "Einzigartige Besucher", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Einzigartige Kunden", + "customers": "Kunden", + "orders": "Bestellungen", + "saved": "Gespeichert", "unknown": "Unbekannt", "untitled": "Unbenannt", + "upgrade": "Upgrade", "update": "Aktualisieren", "url": "URL", "user": "Benutzer", @@ -379,8 +389,8 @@ "confirm-reset": "Sind Sie sicher, dass Sie die Statistiken von {target} zurücksetzen wollen?", "delete-team-warning": "Ein Team zu löschen, wird auch alle Team-Websites löschen.", "delete-website-warning": "Alle zugehörigen Daten werden ebenfalls gelöscht.", - "empty-dashboard": "Ihr Dashboard ist leer. Klicken Sie auf Bearbeiten, um Ihre erste Komponente hinzuzufügen.", "error": "Es ist ein Fehler aufgetreten.", + "empty-dashboard": "Ihr Dashboard ist leer. Klicken Sie auf Bearbeiten, um Ihre erste Komponente hinzuzufügen.", "event-log": "{event} auf {url}", "forbidden": "Verboten", "go-to-settings": "Zu den Einstellungen", @@ -402,6 +412,7 @@ "reset-website": "Um diese Website zurückzusetzen, geben Sie zur Bestätigung {confirmation} in das Feld unten ein.", "reset-website-warning": "Alle Daten für diese Website werden gelöscht, jedoch bleibt der Tracking Code bestehen.", "saved": "Erfolgreich gespeichert.", + "select-board-entity-first": "Wählen Sie zuerst eine Website, einen Pixel oder einen Link aus.", "select-component-preview": "Wählen Sie eine Komponente für die Vorschau", "select-website-first": "Wählen Sie zuerst eine Website", "sever-error": "Serverfehler", @@ -417,6 +428,7 @@ "unauthorized": "Nicht autorisiert", "user-deleted": "Benutzer gelöscht.", "viewed-page": "Seite besucht", + "upgrade-required": "Diese Funktion erfordert ein {plan}-Abonnement.", "visitor-log": "Besucher aus {country} benutzt {browser} auf {os} {device}" } } diff --git a/public/intl/messages/en-GB.json b/public/intl/messages/en-GB.json index b29d7bcf2..9de60575c 100644 --- a/public/intl/messages/en-GB.json +++ b/public/intl/messages/en-GB.json @@ -20,10 +20,8 @@ "all-time": "All time", "analysis": "Analysis", "analytics": "Analytics", - "aov": "AOV", "application": "Application", "apply": "Apply", - "arpu": "ARPU", "attribution": "Attribution", "attribution-description": "See how users engage with your marketing and what drives conversions.", "audience": "Audience", @@ -33,6 +31,7 @@ "behavior": "Behaviour", "block-selector": "Block selector", "boards": "Boards", + "board-type": "Board type", "bounce-rate": "Bounce rate", "breakdown": "Breakdown", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Confirm", "confirm-password": "Confirm password", "contains": "Contains", + "regex-match": "Matches regex", + "regex-not-match": "Does not match regex", "content": "Content", "continue": "Continue", "conversion": "Conversion", @@ -131,8 +132,8 @@ "funnels": "Funnels", "goal": "Goal", "goals": "Goals", - "goals-description": "Track your goals for pageviews and events.", "good": "Good", + "goals-description": "Track your goals for pageviews and events.", "greater-than": "Greater than", "greater-than-equals": "Greater than or equals", "grouped": "Grouped", @@ -140,10 +141,10 @@ "hostname": "Hostname", "hour": "Hour", "includes": "Includes", - "inp": "INP", "insight": "Insight", "insights": "Insights", "insights-description": "Dive deeper into your data by using segments and filters.", + "inp": "INP", "invalid-url": "Invalid URL", "is": "Is", "is-false": "Is false", @@ -177,11 +178,11 @@ "manage": "Manage", "manager": "Manager", "mask-level": "Mask level", + "max": "Max", + "max-duration": "Max duration", "match": "Match", "match-all": "All", "match-any": "Any", - "max": "Max", - "max-duration": "Max duration", "maximize": "Expand", "medium": "Medium", "member": "Member", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {record} other {records}}", "ok": "OK", "online": "Online", + "open": "Mixed", "organic-search": "Organic search", "organic-shopping": "Organic shopping", "organic-social": "Organic social", @@ -212,8 +214,8 @@ "page": "Page", "page-of": "Page {current} of {total}", "page-views": "Page views", - "pages": "Pages", "pageTitle": "Page title", + "pages": "Pages", "paid-ads": "Paid ads", "paid-search": "Paid search", "paid-shopping": "Paid shopping", @@ -225,7 +227,6 @@ "performance": "Performance", "pixel": "Pixel", "pixels": "Pixels", - "play": "Play", "poor": "Poor", "powered-by": "Powered by {name}", "preferences": "Preferences", @@ -246,16 +247,16 @@ "referrers": "Referrers", "refresh": "Refresh", "regenerate": "Regenerate", - "regex-match": "Matches regex", - "regex-not-match": "Does not match regex", "region": "Region", "regions": "Regions", "remaining": "Remaining", "remove": "Remove", "remove-member": "Remove member", + "play": "Play", "replay": "Replay", - "replay-enabled": "Replay enabled", "replay-id": "Replay ID", + "replay-code": "Session replay code", + "replay-enabled": "Replay enabled", "replays": "Replays", "reports": "Reports", "required": "Required", @@ -268,21 +269,24 @@ "revenue-description": "Look into your revenue across time.", "role": "Role", "run-query": "Run query", - "sample-rate": "Sample rate", - "sample-size": "Sample size", "save": "Save", "save-cohort": "Save cohort", + "save-replay": "Save replay", "save-segment": "Save segment", + "sample-rate": "Sample rate", + "sample-size": "Sample size", "screen": "Screen", "screens": "Screens", "search": "Search", "segment": "Segment", "segments": "Segments", "select": "Select", - "select-component": "Select component", + "select-link": "Select link", + "select-pixel": "Select pixel", "select-date": "Select date", "select-filter": "Select filter", "select-role": "Select role", + "select-component": "Select component", "select-website": "Select website", "session": "Session", "session-data": "Session data", @@ -337,9 +341,15 @@ "unique": "Unique", "unique-events": "Unique events", "unique-visitors": "Unique visitors", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unique Customers", + "customers": "Customers", + "orders": "Orders", + "saved": "Saved", "unknown": "Unknown", "untitled": "Untitled", + "upgrade": "Upgrade", "update": "Update", "url": "URL", "user": "User", @@ -379,8 +389,8 @@ "confirm-reset": "Are you sure you want to reset {target}'s statistics?", "delete-team-warning": "Deleting a team will also delete all team websites.", "delete-website-warning": "All associated data will be deleted as well.", - "empty-dashboard": "Your dashboard is empty. Click Edit to add your first component.", "error": "Something went wrong.", + "empty-dashboard": "Your dashboard is empty. Click Edit to add your first component.", "event-log": "{event} on {url}", "forbidden": "Forbidden", "go-to-settings": "Go to settings", @@ -402,6 +412,7 @@ "reset-website": "To reset this website, type {confirmation} in the box below to confirm.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Saved successfully.", + "select-board-entity-first": "Select a website, pixel, or link first.", "select-component-preview": "Select a component to preview", "select-website-first": "Select a website first", "sever-error": "Server error", @@ -417,6 +428,7 @@ "unauthorized": "Unauthorized", "user-deleted": "User deleted.", "viewed-page": "Viewed page", + "upgrade-required": "This feature requires a {plan} plan subscription.", "visitor-log": "Visitor from {country} using {browser} on {os} {device}" } } diff --git a/public/intl/messages/en-US.json b/public/intl/messages/en-US.json index 46ac8d6a0..6614c6500 100644 --- a/public/intl/messages/en-US.json +++ b/public/intl/messages/en-US.json @@ -125,6 +125,8 @@ "filter-combined": "Combined", "filter-raw": "Raw", "filters": "Filters", + "property-filter": "Property Filter", + "activity-by-property": "Activity by property", "first-click": "First click", "first-seen": "First seen", "funnel": "Funnel", @@ -287,6 +289,7 @@ "select-filter": "Select filter", "select-role": "Select role", "select-component": "Select component", + "select-event": "Select an event", "select-website": "Select website", "session": "Session", "session-data": "Session data", diff --git a/public/intl/messages/es-ES.json b/public/intl/messages/es-ES.json index e0923eca6..31861c0b9 100644 --- a/public/intl/messages/es-ES.json +++ b/public/intl/messages/es-ES.json @@ -20,10 +20,8 @@ "all-time": "Todos los tiempos", "analysis": "Análisis", "analytics": "Analíticas", - "aov": "AOV", "application": "Aplicación", "apply": "Aplicar", - "arpu": "ARPU", "attribution": "Atribución", "attribution-description": "Vea cómo los usuarios interactúan con su marketing y qué impulsa las conversiones.", "audience": "Audiencia", @@ -33,6 +31,7 @@ "behavior": "Comportamiento", "block-selector": "Selector de bloque", "boards": "Tableros", + "board-type": "Tipo de tablero", "bounce-rate": "Porcentaje de rebote", "breakdown": "Desglose", "browser": "Navegador", @@ -55,6 +54,8 @@ "confirm": "Confirmar", "confirm-password": "Confirmar contraseña", "contains": "Contiene", + "regex-match": "Coincide con expresión regular", + "regex-not-match": "No coincide con expresión regular", "content": "Contenido", "continue": "Continuar", "conversion": "Conversión", @@ -131,8 +132,8 @@ "funnels": "Embudos", "goal": "Objetivo", "goals": "Objetivos", - "goals-description": "Realice un seguimiento de sus objetivos de páginas vistas y eventos.", "good": "Bueno", + "goals-description": "Realice un seguimiento de sus objetivos de páginas vistas y eventos.", "greater-than": "Mayor que", "greater-than-equals": "Mayor que o igual a", "grouped": "Agrupado", @@ -140,10 +141,10 @@ "hostname": "Nombre de host", "hour": "Hora", "includes": "Incluye", - "inp": "INP", "insight": "Perspectiva", "insights": "Perspectivas", "insights-description": "Profundice en sus datos mediante el uso de segmentos y filtros.", + "inp": "INP", "invalid-url": "URL no válida", "is": "Es igual a", "is-false": "Es falso", @@ -177,11 +178,11 @@ "manage": "Administrar", "manager": "Gerente", "mask-level": "Nivel de máscara", + "max": "Máximo", + "max-duration": "Duración máxima", "match": "Coincidencia", "match-all": "Todo", "match-any": "Cualquiera", - "max": "Máximo", - "max-duration": "Duración máxima", "maximize": "Expandir", "medium": "Medio", "member": "Miembro", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {registro} other {registros}}", "ok": "Aceptar", "online": "En línea", + "open": "Mixto", "organic-search": "Búsqueda orgánica", "organic-shopping": "Compras orgánicas", "organic-social": "Social orgánico", @@ -212,8 +214,8 @@ "page": "Página", "page-of": "Página {current} de {total}", "page-views": "Vistas", - "pages": "Páginas", "pageTitle": "Título de página", + "pages": "Páginas", "paid-ads": "Anuncios pagados", "paid-search": "Búsqueda pagada", "paid-shopping": "Compras pagadas", @@ -225,7 +227,6 @@ "performance": "Rendimiento", "pixel": "Píxel", "pixels": "Píxeles", - "play": "Reproducir", "poor": "Deficiente", "powered-by": "Analíticas de {name}", "preferences": "Preferencias", @@ -246,16 +247,16 @@ "referrers": "Referido desde", "refresh": "Actualizar", "regenerate": "Regenerar", - "regex-match": "Coincide con expresión regular", - "regex-not-match": "No coincide con expresión regular", "region": "Región", "regions": "Regiones", "remaining": "Restante", "remove": "Quitar", "remove-member": "Eliminar miembro", + "play": "Reproducir", "replay": "Repetición", - "replay-enabled": "Repetición activada", "replay-id": "Replay ID", + "replay-code": "Código de repetición de sesión", + "replay-enabled": "Repetición activada", "replays": "Repeticiones", "reports": "Informes", "required": "Obligatorio", @@ -266,24 +267,26 @@ "retention-description": "Medir la frecuencia con la que los usuarios vuelven a tu sitio web.", "revenue": "Ganancias", "revenue-description": "Analice sus ganancias a lo largo del tiempo.", - "revenue-property": "Propiedad de ganancias", "role": "Rol", "run-query": "Ejecutar consulta", - "sample-rate": "Tasa de muestreo", - "sample-size": "Tamaño de muestra", "save": "Guardar", "save-cohort": "Guardar cohorte", + "save-replay": "Guardar repetición", "save-segment": "Guardar segmento", + "sample-rate": "Tasa de muestreo", + "sample-size": "Tamaño de muestra", "screen": "Pantalla", "screens": "Pantallas", "search": "Buscar", "segment": "Segmento", "segments": "Segmentos", "select": "Seleccionar", - "select-component": "Seleccionar componente", + "select-link": "Seleccionar enlace", + "select-pixel": "Seleccionar píxel", "select-date": "Seleccionar fecha", "select-filter": "Seleccionar filtro", "select-role": "Seleccionar rol", + "select-component": "Seleccionar componente", "select-website": "Seleccionar sitio web", "session": "Sesión", "session-data": "Datos de sesión", @@ -338,13 +341,18 @@ "unique": "Único", "unique-events": "Eventos únicos", "unique-visitors": "Visitantes únicos", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clientes únicos", + "customers": "Clientes", + "orders": "Pedidos", + "saved": "Guardado", "unknown": "Desconocida", "untitled": "Sin título", + "upgrade": "Actualizar", "update": "Actualizar", "url": "URL", "user": "Usuario", - "user-property": "Propiedad de usuario", "username": "Nombre de usuario", "users": "Usuarios", "utm": "UTM", @@ -368,7 +376,9 @@ "website-id": "ID del sitio web", "websites": "Sitios web", "window": "Ventana", - "yesterday": "Ayer" + "yesterday": "Ayer", + "revenue-property": "Propiedad de ganancias", + "user-property": "Propiedad de usuario" }, "message": { "action-confirmation": "Escriba {confirmation} en el cuadro a continuación para confirmar.", @@ -381,8 +391,8 @@ "confirm-reset": "¿Seguro que quieres BORRAR las analíticas de {target}?", "delete-team-warning": "Al eliminar un equipo, también se eliminarán todos los sitios web del equipo.", "delete-website-warning": "Toda la información relacionada será eliminada.", - "empty-dashboard": "Tu panel está vacío. Haz clic en Editar para añadir tu primer componente.", "error": "Algo falló.", + "empty-dashboard": "Tu panel está vacío. Haz clic en Editar para añadir tu primer componente.", "event-log": "{event} en {url}", "forbidden": "Prohibido", "go-to-settings": "Ir a la configuración", @@ -404,6 +414,7 @@ "reset-website": "Para reiniciar este sitio web, escribe {confirmation} a continuación para confirmar.", "reset-website-warning": "Todas las estadísticas de esta página serán eliminadas, pero el código de rastreo permanecerá intacto.", "saved": "Guardado", + "select-board-entity-first": "Selecciona primero un sitio web, píxel o enlace.", "select-component-preview": "Selecciona un componente para previsualizar", "select-website-first": "Selecciona un sitio web primero", "sever-error": "Error del servidor", @@ -419,6 +430,7 @@ "unauthorized": "No autorizado", "user-deleted": "Usuario eliminado.", "viewed-page": "Página vista", + "upgrade-required": "Esta función requiere una suscripción al plan {plan}.", "visitor-log": "Visitante desde {country} usando {browser} en {os} {device}" } } diff --git a/public/intl/messages/fi-FI.json b/public/intl/messages/fi-FI.json index 4dfc671b9..049906bf3 100644 --- a/public/intl/messages/fi-FI.json +++ b/public/intl/messages/fi-FI.json @@ -20,10 +20,8 @@ "all-time": "Alusta lähtien", "analysis": "Analyysi", "analytics": "Analytiikka", - "aov": "AOV", "application": "Sovellus", "apply": "Käytä", - "arpu": "ARPU", "attribution": "Attribuutio", "attribution-description": "Katso, miten käyttäjät ovat vuorovaikutuksessa markkinointisi kanssa ja mikä johtaa konversioihin.", "audience": "Yleisö", @@ -33,6 +31,7 @@ "behavior": "Käyttäytyminen", "block-selector": "Lohkovalitsin", "boards": "Taulut", + "board-type": "Taulun tyyppi", "bounce-rate": "Välitön poistuminen", "breakdown": "Erittele", "browser": "Selain", @@ -55,6 +54,8 @@ "confirm": "Vahvista", "confirm-password": "Vahvista salasana", "contains": "Sisältää", + "regex-match": "Vastaa säännöllistä lauseketta", + "regex-not-match": "Ei vastaa säännöllistä lauseketta", "content": "Sisältö", "continue": "Jatka", "conversion": "Konversio", @@ -131,8 +132,8 @@ "funnels": "Suppilot", "goal": "Tavoite", "goals": "Tavoitteet", - "goals-description": "Seuraa sivun katselujen ja tapahtumien tavoitteitasi.", "good": "Hyvä", + "goals-description": "Seuraa sivun katselujen ja tapahtumien tavoitteitasi.", "greater-than": "Suurempi kuin", "greater-than-equals": "Suurempi tai yhtä suuri kuin", "grouped": "Ryhmitelty", @@ -140,10 +141,10 @@ "hostname": "Isäntänimi", "hour": "Tunti", "includes": "Sisältää", - "inp": "INP", "insight": "Oivallus", "insights": "Oivallukset", "insights-description": "Sukella syvemmälle tietoihisi käyttämällä segmenttejä ja suodattimia.", + "inp": "INP", "invalid-url": "Virheellinen URL", "is": "On", "is-false": "On epätosi", @@ -177,11 +178,11 @@ "manage": "Hallinnoi", "manager": "Päällikkö", "mask-level": "Maskitaso", + "max": "Maksimi", + "max-duration": "Enimmäiskesto", "match": "Vastaavuus", "match-all": "Kaikki", "match-any": "Mikä tahansa", - "max": "Maksimi", - "max-duration": "Enimmäiskesto", "maximize": "Laajenna", "medium": "Keskitaso", "member": "Jäsen", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {tietue} other {tietuetta}}", "ok": "OK", "online": "Verkossa", + "open": "Sekalainen", "organic-search": "Orgaaninen haku", "organic-shopping": "Orgaaninen ostaminen", "organic-social": "Orgaaninen sosiaalinen", @@ -212,8 +214,8 @@ "page": "Sivu", "page-of": "Sivu {current} / {total}", "page-views": "Sivun näyttökerrat", - "pages": "Sivut", "pageTitle": "Sivun otsikko", + "pages": "Sivut", "paid-ads": "Maksetut mainokset", "paid-search": "Maksettu haku", "paid-shopping": "Maksettu ostaminen", @@ -225,7 +227,6 @@ "performance": "Suorituskyky", "pixel": "Pikseli", "pixels": "Pikselit", - "play": "Toista", "poor": "Huono", "powered-by": "Voimanlähteenä {name}", "preferences": "Asetukset", @@ -246,16 +247,16 @@ "referrers": "Viittaajat", "refresh": "Päivitä", "regenerate": "Luo uudelleen", - "regex-match": "Vastaa säännöllistä lauseketta", - "regex-not-match": "Ei vastaa säännöllistä lauseketta", "region": "Alue", "regions": "Alueet", "remaining": "Jäljellä", "remove": "Poista", "remove-member": "Poista jäsen", + "play": "Toista", "replay": "Toisto", - "replay-enabled": "Toisto käytössä", "replay-id": "Replay ID", + "replay-code": "Istunnon toistokoodi", + "replay-enabled": "Toisto käytössä", "replays": "Toistot", "reports": "Raportit", "required": "Vaaditaan", @@ -268,21 +269,24 @@ "revenue-description": "Katso tulosi ajan mittaan.", "role": "Rooli", "run-query": "Suorita kysely", - "sample-rate": "Näytteenottotaajuus", - "sample-size": "Otoskoko", "save": "Tallenna", "save-cohort": "Tallenna kohortti", + "save-replay": "Tallenna toisto", "save-segment": "Tallenna segmentti", + "sample-rate": "Näytteenottotaajuus", + "sample-size": "Otoskoko", "screen": "Näyttö", "screens": "Näytöt", "search": "Haku", "segment": "Segmentti", "segments": "Segmentit", "select": "Valitse", - "select-component": "Valitse komponentti", + "select-link": "Valitse linkki", + "select-pixel": "Valitse pikseli", "select-date": "Valitse päivämäärä", "select-filter": "Valitse suodatin", "select-role": "Valitse rooli", + "select-component": "Valitse komponentti", "select-website": "Valitse verkkosivu", "session": "Istunto", "session-data": "Istuntotiedot", @@ -337,9 +341,15 @@ "unique": "Uniikki", "unique-events": "Uniikit tapahtumat", "unique-visitors": "Yksittäiset kävijät", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Uniikit asiakkaat", + "customers": "Asiakkaat", + "orders": "Tilaukset", + "saved": "Tallennettu", "unknown": "Tuntematon", "untitled": "Nimetön", + "upgrade": "Päivitä", "update": "Päivitä", "url": "URL", "user": "Käyttäjä", @@ -379,8 +389,8 @@ "confirm-reset": "Haluatko varmasti poistaa sivuston {target} tilastot?", "delete-team-warning": "Tiimin poistaminen poistaa myös kaikki tiimin sivustot.", "delete-website-warning": "Kaikki siihen liittyvät tiedot poistetaan.", - "empty-dashboard": "Koontinäyttösi on tyhjä. Napsauta Muokkaa lisätäksesi ensimmäisen komponentin.", "error": "Jotain meni pieleen.", + "empty-dashboard": "Koontinäyttösi on tyhjä. Napsauta Muokkaa lisätäksesi ensimmäisen komponentin.", "event-log": "{event} sivulla {url}", "forbidden": "Kielletty", "go-to-settings": "Mene asetuksiin", @@ -402,6 +412,7 @@ "reset-website": "Nollaa verkkosivusto kirjoittamalla {confirmation} alla olevaan kenttään vahvistaaksesi.", "reset-website-warning": "Kaikki sivuston tilastot poistetaan, mutta seurantakoodi pysyy muuttumattomana.", "saved": "Tallennettu onnistuneesti.", + "select-board-entity-first": "Valitse ensin verkkosivusto, pikseli tai linkki.", "select-component-preview": "Valitse komponentti esikatselua varten", "select-website-first": "Valitse ensin verkkosivusto", "sever-error": "Palvelinvirhe", @@ -417,6 +428,7 @@ "unauthorized": "Ei oikeuksia", "user-deleted": "Käyttäjä poistettu.", "viewed-page": "Katsottu sivu", + "upgrade-required": "Tämä ominaisuus vaatii {plan}-tilauksen.", "visitor-log": "Vierailija maasta {country} selaimella {browser} laitteella {os} {device}" } } diff --git a/public/intl/messages/fo-FO.json b/public/intl/messages/fo-FO.json index b765e78a5..e01a37717 100644 --- a/public/intl/messages/fo-FO.json +++ b/public/intl/messages/fo-FO.json @@ -20,10 +20,8 @@ "all-time": "Allur tíðin", "analysis": "Greining", "analytics": "Greining", - "aov": "AOV", "application": "Forrit", "apply": "Nýt", - "arpu": "ARPU", "attribution": "Áseting", "attribution-description": "Síggj hvussu brúkarar samskifta við marknaðarføringina og hvat førir til umvendingar.", "audience": "Áhoyrarar", @@ -33,6 +31,7 @@ "behavior": "Atferð", "block-selector": "Blokkveljari", "boards": "Borð", + "board-type": "Slag av brætti", "bounce-rate": "Bounce prosenttal", "breakdown": "Sundurgreining", "browser": "Kagi", @@ -55,6 +54,8 @@ "confirm": "Staðfest", "confirm-password": "Vátta loyniorð", "contains": "Inniheldur", + "regex-match": "Samsvarar við regluligan úttrykk", + "regex-not-match": "Samsvarar ikki við regluligan úttrykk", "content": "Innihald", "continue": "Halt fram", "conversion": "Umvending", @@ -131,8 +132,8 @@ "funnels": "Traktarar", "goal": "Mál", "goals": "Mál", - "goals-description": "Fylg við málum fyri síðuvísingar og tiltøk.", "good": "Gott", + "goals-description": "Fylg við málum fyri síðuvísingar og tiltøk.", "greater-than": "Størri enn", "greater-than-equals": "Størri ella javnt", "grouped": "Bólkað", @@ -140,10 +141,10 @@ "hostname": "Vertnavn", "hour": "Tími", "includes": "Inniheldur", - "inp": "INP", "insight": "Innlit", "insights": "Innlit", "insights-description": "Fá meira innlit í tínar dátur við at brúka bólkar og síur.", + "inp": "INP", "invalid-url": "Ógild URL", "is": "Er", "is-false": "Er falskt", @@ -177,11 +178,11 @@ "manage": "Stýra", "manager": "Stjóri", "mask-level": "Maskustig", + "max": "Mest", + "max-duration": "Mesta tíðarlongd", "match": "Samsvørun", "match-all": "Allt", "match-any": "Nakað", - "max": "Mest", - "max-duration": "Mesta tíðarlongd", "maximize": "Víðka", "medium": "Miðal", "member": "Limur", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {skrá} other {skrár}}", "ok": "OK", "online": "Online", + "open": "Blandað", "organic-search": "Organisk leiting", "organic-shopping": "Organisk keyp", "organic-social": "Organisk sosial miðla", @@ -212,8 +214,8 @@ "page": "Síða", "page-of": "Síða {current} av {total}", "page-views": "Opnaðar síðir", - "pages": "Síðir", "pageTitle": "Síðuheiti", + "pages": "Síðir", "paid-ads": "Goldnar lýsingar", "paid-search": "Goldin leiting", "paid-shopping": "Goldið keyp", @@ -225,7 +227,6 @@ "performance": "Effektivni", "pixel": "Piksel", "pixels": "Pikslur", - "play": "Spæla", "poor": "Dårligt", "powered-by": "Rikið av {name}", "preferences": "Stillingar", @@ -246,16 +247,16 @@ "referrers": "Framsendingar", "refresh": "Dagfør", "regenerate": "Endurskapa", - "regex-match": "Samsvarar við regluligan úttrykk", - "regex-not-match": "Samsvarar ikki við regluligan úttrykk", "region": "Øki", "regions": "Øki", "remaining": "Eftir", "remove": "Fjern", "remove-member": "Fjern lim", + "play": "Spæla", "replay": "Uppspæling", - "replay-enabled": "Uppspæling virkjað", "replay-id": "Replay ID", + "replay-code": "Kodi fyri endurspæling av setuni", + "replay-enabled": "Uppspæling virkjað", "replays": "Uppspælingar", "reports": "Frágreiðingar", "required": "Kravið", @@ -268,21 +269,24 @@ "revenue-description": "Fá yvirlit yvir inntøku yvir tíð.", "role": "Leiklutur", "run-query": "Koyr fyrispurning", - "sample-rate": "Samplingartiðindi", - "sample-size": "Samplingarstødd", "save": "Goym", "save-cohort": "Goym kohortu", + "save-replay": "Goym endurspælingina", "save-segment": "Goym segment", + "sample-rate": "Samplingartiðindi", + "sample-size": "Samplingarstødd", "screen": "Skíggi", "screens": "Skíggjar", "search": "Leita", "segment": "Segment", "segments": "Segment", "select": "Vel", - "select-component": "Vel eina íhlut", + "select-link": "Vel leinkju", + "select-pixel": "Vel pixil", "select-date": "Vel dato", "select-filter": "Vel síu", "select-role": "Vel leiklut", + "select-component": "Vel eina íhlut", "select-website": "Vel heimasíðu", "session": "Seta", "session-data": "Setudáta", @@ -337,9 +341,15 @@ "unique": "Einstaklingar", "unique-events": "Einstakar hendingar", "unique-visitors": "Einsýna vitjanir", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Einstakar kundar", + "customers": "Kundar", + "orders": "Bílegging", + "saved": "Goymt", "unknown": "Ókent", "untitled": "Einki heiti", + "upgrade": "Dagfør", "update": "Dagfør", "url": "URL", "user": "Brúkari", @@ -379,8 +389,8 @@ "confirm-reset": "Are your sure you want to reset {target}'s statistics?", "delete-team-warning": "At strika eitt lið strikar eisini allar heimasíður hjá liðnum.", "delete-website-warning": "Øll data ið er knýtt at verður eisini strika.", - "empty-dashboard": "Stjórnarborðið títt er tómt. Trýst á Rætta fyri at leggja afturat fyrstu íhlut.", "error": "Okkurt bleiv gali.", + "empty-dashboard": "Stjórnarborðið títt er tómt. Trýst á Rætta fyri at leggja afturat fyrstu íhlut.", "event-log": "{event} á {url}", "forbidden": "Forboðið", "go-to-settings": "Far til stillingar", @@ -402,6 +412,7 @@ "reset-website": "Fyri at nullstilla hesa heimasíðu, skriva {confirmation} í teigin niðanfyri at vátta.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Goymt.", + "select-board-entity-first": "Vel fyrst heimasíðu, pixil ella leinkju.", "select-component-preview": "Vel eina íhlut at forskoða", "select-website-first": "Vel fyrst eina heimasíðu", "sever-error": "Ambætaravilla", @@ -417,6 +428,7 @@ "unauthorized": "Ikki góðkent", "user-deleted": "Brúkari strikaður.", "viewed-page": "Síð vís", + "upgrade-required": "Hesin virknisháttur krevur eitt {plan}-lyftirtak.", "visitor-log": "Vitjandi frá {country} brúkar {browser} á {os} {device}" } } diff --git a/public/intl/messages/fr-FR.json b/public/intl/messages/fr-FR.json index 665651451..982370683 100644 --- a/public/intl/messages/fr-FR.json +++ b/public/intl/messages/fr-FR.json @@ -33,6 +33,7 @@ "behavior": "Comportement", "block-selector": "Sélecteur de bloc", "boards": "Tableaux", + "board-type": "Type de tableau", "bounce-rate": "Taux de rebond", "breakdown": "Répartition", "browser": "Navigateur", @@ -74,6 +75,7 @@ "current": "Actuel", "current-password": "Mot de passe actuel", "custom-range": "Période personnalisée", + "customers": "Clients", "dashboard": "Tableau de bord", "data": "Données", "date": "Date", @@ -201,6 +203,8 @@ "number-of-records": "{x} {x, plural, one {enregistrement} other {enregistrements}}", "ok": "OK", "online": "En ligne", + "open": "Mixte", + "orders": "Commandes", "organic-search": "Recherche organique", "organic-shopping": "Achat organique", "organic-social": "Réseau social organique", @@ -254,6 +258,7 @@ "remove": "Retirer", "remove-member": "Retirer le membre", "replay": "Relecture", + "replay-code": "Code de relecture de session", "replay-enabled": "Relecture activée", "replay-id": "Replay ID", "replays": "Relectures", @@ -272,7 +277,9 @@ "sample-size": "Taille de l'échantillon", "save": "Enregistrer", "save-cohort": "Enregistrer la cohorte", + "save-replay": "Enregistrer la relecture", "save-segment": "Enregistrer le segment", + "saved": "Enregistré", "screen": "Écran", "screens": "Écrans", "search": "Rechercher", @@ -282,6 +289,8 @@ "select-component": "Sélectionner un composant", "select-date": "Choisir une période", "select-filter": "Sélectionner un filtre", + "select-link": "Sélectionner un lien", + "select-pixel": "Sélectionner un pixel", "select-role": "Choisir un rôle", "select-website": "Choisir un site", "session": "Session", @@ -341,6 +350,7 @@ "unknown": "Inconnu", "untitled": "Sans titre", "update": "Modifier", + "upgrade": "Mettre à niveau", "url": "URL", "user": "Utilisateur", "username": "Nom d'utilisateur", @@ -402,6 +412,7 @@ "reset-website": "Pour réinitialiser ce site, taper {confirmation} ci-dessous pour confirmer.", "reset-website-warning": "Toutes les statistiques pour ce site seront supprimées, mais votre code de suivi restera intact.", "saved": "Enregistré.", + "select-board-entity-first": "Sélectionnez d'abord un site, un pixel ou un lien.", "select-component-preview": "Sélectionnez un composant pour le prévisualiser", "select-website-first": "Sélectionnez d'abord un site web", "sever-error": "Erreur serveur", @@ -415,6 +426,7 @@ "transfer-website": "Transférer la propriété du site sur votre compte ou à une autre équipe.", "triggered-event": "Évènement déclenché", "unauthorized": "Non authorisé!", + "upgrade-required": "Cette fonctionnalité nécessite un abonnement {plan}.", "user-deleted": "Utilisateur supprimé.", "viewed-page": "Page vue", "visitor-log": "Visiteur de {country} utilisant {browser} sur {os} {device}" diff --git a/public/intl/messages/ga-ES.json b/public/intl/messages/ga-ES.json index 6c92798aa..a9e180864 100644 --- a/public/intl/messages/ga-ES.json +++ b/public/intl/messages/ga-ES.json @@ -20,10 +20,8 @@ "all-time": "Sempre", "analysis": "Análise", "analytics": "Analíticas", - "aov": "AOV", "application": "Aplicación", "apply": "Aplicar", - "arpu": "ARPU", "attribution": "Atribución", "attribution-description": "Vexa como os usuarios interactúan co seu márketing e que impulsa as conversións.", "audience": "Audiencia", @@ -33,6 +31,7 @@ "behavior": "Comportamento", "block-selector": "Selector de bloque", "boards": "Taboleiros", + "board-type": "Tipo de taboleiro", "bounce-rate": "Proporción de rebote", "breakdown": "Desglose", "browser": "Navegador", @@ -55,6 +54,8 @@ "confirm": "Confirmar", "confirm-password": "Confirmar contrasinal", "contains": "Contén", + "regex-match": "Meaitseálann sé le slonn rialta", + "regex-not-match": "Ní mheaitseálann sé le slonn rialta", "content": "Contido", "continue": "Continuar", "conversion": "Conversión", @@ -131,8 +132,8 @@ "funnels": "Funís", "goal": "Obxectivo", "goals": "Obxectivos", - "goals-description": "Segue os teus obxectivos de visualizacións de páxinas e eventos.", "good": "Bo", + "goals-description": "Segue os teus obxectivos de visualizacións de páxinas e eventos.", "greater-than": "Maior que", "greater-than-equals": "Maior ou igual que", "grouped": "Agrupado", @@ -140,10 +141,10 @@ "hostname": "Nome do host", "hour": "Hora", "includes": "Inclúe", - "inp": "INP", "insight": "Información", "insights": "Informacións", "insights-description": "Afonda nos teus datos usando segmentos e filtros.", + "inp": "INP", "invalid-url": "URL non válida", "is": "É", "is-false": "É falso", @@ -177,11 +178,11 @@ "manage": "Xestionar", "manager": "Xestor", "mask-level": "Nivel de máscara", + "max": "Máx", + "max-duration": "Duración máxima", "match": "Coincidencia", "match-all": "Todo", "match-any": "Calquera", - "max": "Máx", - "max-duration": "Duración máxima", "maximize": "Expandir", "medium": "Medio", "member": "Membro", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {rexistro} other {rexistros}}", "ok": "Aceptar", "online": "En liña", + "open": "Mixto", "organic-search": "Busca orgánica", "organic-shopping": "Compra orgánica", "organic-social": "Social orgánico", @@ -212,8 +214,8 @@ "page": "Páxina", "page-of": "Páxina {current} de {total}", "page-views": "Vistas de páxinas", - "pages": "Páxinas", "pageTitle": "Título da páxina", + "pages": "Páxinas", "paid-ads": "Anuncios de pago", "paid-search": "Busca de pago", "paid-shopping": "Compra de pago", @@ -225,7 +227,6 @@ "performance": "Rendemento", "pixel": "Píxel", "pixels": "Píxeles", - "play": "Reproducir", "poor": "Deficiente", "powered-by": "Funciona grazas a {name}", "preferences": "Preferencias", @@ -246,16 +247,16 @@ "referrers": "Orixes", "refresh": "Actualizar", "regenerate": "Rexenerar", - "regex-match": "Meaitseálann sé le slonn rialta", - "regex-not-match": "Ní mheaitseálann sé le slonn rialta", "region": "Rexión", "regions": "Rexións", "remaining": "Restante", "remove": "Eliminar", "remove-member": "Eliminar membro", + "play": "Reproducir", "replay": "Reprodución", - "replay-enabled": "Reprodución activada", "replay-id": "Replay ID", + "replay-code": "Código de repetición da sesión", + "replay-enabled": "Reprodución activada", "replays": "Reproducións", "reports": "Reportes", "required": "Requerido", @@ -268,21 +269,24 @@ "revenue-description": "Consulta os teus ingresos ao longo do tempo.", "role": "Rol", "run-query": "Executar petición", - "sample-rate": "Taxa de mostraxe", - "sample-size": "Tamaño da mostra", "save": "Gardar", "save-cohort": "Gardar cohorte", + "save-replay": "Gardar repetición", "save-segment": "Gardar segmento", + "sample-rate": "Taxa de mostraxe", + "sample-size": "Tamaño da mostra", "screen": "Pantalla", "screens": "Pantallas", "search": "Buscar", "segment": "Segmento", "segments": "Segmentos", "select": "Seleccionar", - "select-component": "Seleccionar compoñente", + "select-link": "Seleccionar ligazón", + "select-pixel": "Seleccionar píxel", "select-date": "Seleccionar data", "select-filter": "Seleccionar filtro", "select-role": "Seleccionar rol", + "select-component": "Seleccionar compoñente", "select-website": "Seleccionar sitio web", "session": "Sesión", "session-data": "Datos da sesión", @@ -337,9 +341,15 @@ "unique": "Único", "unique-events": "Eventos únicos", "unique-visitors": "Visitas únicas", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clientes únicos", + "customers": "Clientes", + "orders": "Pedidos", + "saved": "Gardado", "unknown": "Descoñecido", "untitled": "Sen título", + "upgrade": "Actualizar", "update": "Actualizar", "url": "URL", "user": "Usuario", @@ -379,8 +389,8 @@ "confirm-reset": "Estás seguro/a de querer restablecer as estatísticas de {target}?", "delete-team-warning": "Eliminar un equipo tamén eliminará tódolos sitios web do equipo.", "delete-website-warning": "Tamén serán borrados tódolos datos asociados.", - "empty-dashboard": "O teu panel está baleiro. Fai clic en Editar para engadir o teu primeiro compoñente.", "error": "Houbo un fallo.", + "empty-dashboard": "O teu panel está baleiro. Fai clic en Editar para engadir o teu primeiro compoñente.", "event-log": "{event} en {url}", "forbidden": "Prohibido", "go-to-settings": "Ir aos axustes", @@ -402,6 +412,7 @@ "reset-website": "Para restablecer este sitio web, escriba {confirmation} na caixa de embaixo para confirmar.", "reset-website-warning": "Vanse eliminar tódalas estatísticas deste sitio web, pero o código de seguimento permanecerá sen cambios.", "saved": "Gardouse correctamente.", + "select-board-entity-first": "Seleccione primeiro un sitio web, píxel ou ligazón.", "select-component-preview": "Selecciona un compoñente para previsualizar", "select-website-first": "Selecciona primeiro un sitio web", "sever-error": "Erro do servidor", @@ -417,6 +428,7 @@ "unauthorized": "Non autorizado", "user-deleted": "Usuario eliminado.", "viewed-page": "Páxina vista", + "upgrade-required": "Esta función require unha subscrición ao plan {plan}.", "visitor-log": "Visitante desde {country} usando {browser} en {os} {device}" } } diff --git a/public/intl/messages/hr-HR.json b/public/intl/messages/hr-HR.json index e21f32fda..963b86a50 100644 --- a/public/intl/messages/hr-HR.json +++ b/public/intl/messages/hr-HR.json @@ -20,10 +20,8 @@ "all-time": "Svo vrijeme", "analysis": "Analiza", "analytics": "Analitika", - "aov": "AOV", "application": "Aplikacija", "apply": "Primijeni", - "arpu": "ARPU", "attribution": "Atribucija", "attribution-description": "Pogledajte kako korisnici komuniciraju s vašim marketingom i što dovodi do konverzija.", "audience": "Publika", @@ -33,6 +31,7 @@ "behavior": "Ponašanje", "block-selector": "Odabir bloka", "boards": "Ploče", + "board-type": "Vrsta ploče", "bounce-rate": "Stopa napuštanja", "breakdown": "Raspad", "browser": "Preglednik", @@ -55,6 +54,8 @@ "confirm": "Potvrdi", "confirm-password": "Potvrdi lozinku", "contains": "Sadrži", + "regex-match": "Odgovara regularnom izrazu", + "regex-not-match": "Ne odgovara regularnom izrazu", "content": "Sadržaj", "continue": "Nastavi", "conversion": "Konverzija", @@ -131,8 +132,8 @@ "funnels": "Ljevci", "goal": "Cilj", "goals": "Ciljevi", - "goals-description": "Pratite svoje ciljeve za prikaze stranica i događaje.", "good": "Dobro", + "goals-description": "Pratite svoje ciljeve za prikaze stranica i događaje.", "greater-than": "Veće od", "greater-than-equals": "Veće ili jednako", "grouped": "Grupirano", @@ -140,10 +141,10 @@ "hostname": "Naziv hosta", "hour": "Sat", "includes": "Uključuje", - "inp": "INP", "insight": "Uvid", "insights": "Uvidi", "insights-description": "Dublje analizirajte svoje podatke pomoću segmenata i filtera.", + "inp": "INP", "invalid-url": "Nevaljani URL", "is": "Je", "is-false": "Je netočno", @@ -177,11 +178,11 @@ "manage": "Upravljaj", "manager": "Upravitelj", "mask-level": "Razina maske", + "max": "Maksimum", + "max-duration": "Maksimalno trajanje", "match": "Podudaranje", "match-all": "Sve", "match-any": "Bilo koje", - "max": "Maksimum", - "max-duration": "Maksimalno trajanje", "maximize": "Proširi", "medium": "Srednje", "member": "Član", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {zapis} other {zapisa}}", "ok": "U redu", "online": "Na mreži", + "open": "Miješano", "organic-search": "Organsko pretraživanje", "organic-shopping": "Organska kupovina", "organic-social": "Organska društvena mreža", @@ -212,8 +214,8 @@ "page": "Stranica", "page-of": "Stranica {current} od {total}", "page-views": "Pregledi stranica", - "pages": "Stranice", "pageTitle": "Naslov stranice", + "pages": "Stranice", "paid-ads": "Plaćeni oglasi", "paid-search": "Plaćeno pretraživanje", "paid-shopping": "Plaćena kupovina", @@ -225,7 +227,6 @@ "performance": "Performanse", "pixel": "Piksel", "pixels": "Pikseli", - "play": "Reproduciraj", "poor": "Loše", "powered-by": "Pokreće {name}", "preferences": "Postavke", @@ -246,16 +247,16 @@ "referrers": "Izvori preporuke", "refresh": "Osvježi", "regenerate": "Regeneriraj", - "regex-match": "Odgovara regularnom izrazu", - "regex-not-match": "Ne odgovara regularnom izrazu", "region": "Regija", "regions": "Regije", "remaining": "Preostalo", "remove": "Ukloni", "remove-member": "Ukloni člana", + "play": "Reproduciraj", "replay": "Ponovna reprodukcija", - "replay-enabled": "Ponovna reprodukcija omogućena", "replay-id": "Replay ID", + "replay-code": "Kôd ponavljanja sesije", + "replay-enabled": "Ponovna reprodukcija omogućena", "replays": "Ponovne reprodukcije", "reports": "Izvješća", "required": "Potrebna", @@ -268,21 +269,24 @@ "revenue-description": "Pogledajte svoj prihod tijekom vremena.", "role": "Uloga", "run-query": "Pokreni upit", - "sample-rate": "Stopa uzorkovanja", - "sample-size": "Veličina uzorka", "save": "Spremi", "save-cohort": "Spremi kohortu", + "save-replay": "Spremi ponavljanje", "save-segment": "Spremi segment", + "sample-rate": "Stopa uzorkovanja", + "sample-size": "Veličina uzorka", "screen": "Zaslon", "screens": "Ekrani", "search": "Pretraži", "segment": "Segment", "segments": "Segmenti", "select": "Odaberi", - "select-component": "Odaberite komponentu", + "select-link": "Odaberi poveznicu", + "select-pixel": "Odaberi piksel", "select-date": "Odaberi datum", "select-filter": "Odaberi filter", "select-role": "Odaberi ulogu", + "select-component": "Odaberite komponentu", "select-website": "Odaberi web stranicu", "session": "Sesija", "session-data": "Podaci sesije", @@ -337,9 +341,15 @@ "unique": "Jedinstveni", "unique-events": "Jedinstveni događaji", "unique-visitors": "Jedinstveni posjetitelji", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Jedinstveni kupci", + "customers": "Kupci", + "orders": "Narudžbe", + "saved": "Spremljeno", "unknown": "Nepoznato", "untitled": "Bez naslova", + "upgrade": "Nadogradi", "update": "Ažuriraj", "url": "URL", "user": "Korisnik", @@ -379,8 +389,8 @@ "confirm-reset": "Jeste li sigurni da želite resetirati {target}'s statistiku?", "delete-team-warning": "Brisanje tima će izbrisati i sve web stranice tima.", "delete-website-warning": "Svi podaci web stranice bit će izbrisani.", - "empty-dashboard": "Vaša nadzorna ploča je prazna. Kliknite Uredi da dodate prvu komponentu.", "error": "Nešto je pošlo po krivu.", + "empty-dashboard": "Vaša nadzorna ploča je prazna. Kliknite Uredi da dodate prvu komponentu.", "event-log": "{event} na {url}", "forbidden": "Zabranjeno", "go-to-settings": "Idi u postavke", @@ -402,6 +412,7 @@ "reset-website": "Za resetiranje ove web stranice upišite {confirmation} u polje ispod.", "reset-website-warning": "Svi statistički podaci za ovu web stranicu bit će izbrisani, ali vaše postavke ostaju netaknute.", "saved": "Spremljeno.", + "select-board-entity-first": "Prvo odaberite web-mjesto, piksel ili poveznicu.", "select-component-preview": "Odaberite komponentu za pregled", "select-website-first": "Prvo odaberite web stranicu", "sever-error": "Greška poslužitelja", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizirano", "user-deleted": "Korisnik izbrisan.", "viewed-page": "Pregledana stranica", + "upgrade-required": "Ova značajka zahtijeva pretplatu na plan {plan}.", "visitor-log": "Posjetitelj iz {country} koristi {browser} na {os} {device}" } } diff --git a/public/intl/messages/hu-HU.json b/public/intl/messages/hu-HU.json index 5315d3e72..aea98d3b2 100644 --- a/public/intl/messages/hu-HU.json +++ b/public/intl/messages/hu-HU.json @@ -20,10 +20,8 @@ "all-time": "Minden időszak", "analysis": "Elemzés", "analytics": "Analitika", - "aov": "AOV", "application": "Alkalmazás", "apply": "Alkalmaz", - "arpu": "ARPU", "attribution": "Attribúció", "attribution-description": "Nézze meg, hogyan lépnek kapcsolatba a felhasználók a marketingjével, és mi vezet konverzióhoz.", "audience": "Közönség", @@ -33,6 +31,7 @@ "behavior": "Viselkedés", "block-selector": "Blokk kiválasztó", "boards": "Táblák", + "board-type": "Tábla típusa", "bounce-rate": "Visszafordulási arány", "breakdown": "Bontás", "browser": "Böngésző", @@ -55,6 +54,8 @@ "confirm": "Megerősít", "confirm-password": "Jelszó megerősítése", "contains": "Tartalmazza", + "regex-match": "Illeszkedik a reguláris kifejezésre", + "regex-not-match": "Nem illeszkedik a reguláris kifejezésre", "content": "Tartalom", "continue": "Folytatás", "conversion": "Konverzió", @@ -131,8 +132,8 @@ "funnels": "Tölcsérek", "goal": "Cél", "goals": "Célok", - "goals-description": "Kövesse nyomon a céljait oldalmegtekintések és események alapján.", "good": "Jó", + "goals-description": "Kövesse nyomon a céljait oldalmegtekintések és események alapján.", "greater-than": "Nagyobb mint", "greater-than-equals": "Nagyobb vagy egyenlő", "grouped": "Csoportosítva", @@ -140,10 +141,10 @@ "hostname": "Hosztnév", "hour": "Óra", "includes": "Tartalmazza", - "inp": "INP", "insight": "Betekintés", "insights": "Betekintések", "insights-description": "Merüljön el mélyebben az adataiban szegmensek és szűrők használatával.", + "inp": "INP", "invalid-url": "Érvénytelen URL", "is": "Az", "is-false": "Hamis", @@ -177,11 +178,11 @@ "manage": "Kezelés", "manager": "Menedzser", "mask-level": "Maszkolási szint", + "max": "Maximum", + "max-duration": "Maximális időtartam", "match": "Egyezés", "match-all": "Összes", "match-any": "Bármelyik", - "max": "Maximum", - "max-duration": "Maximális időtartam", "maximize": "Kibontás", "medium": "Közepes", "member": "Tag", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {rekord} other {rekord}}", "ok": "OK", "online": "Online", + "open": "Vegyes", "organic-search": "Organikus keresés", "organic-shopping": "Organikus vásárlás", "organic-social": "Organikus közösségi", @@ -212,8 +214,8 @@ "page": "Oldal", "page-of": "Oldal {current} / {total}", "page-views": "Oldalmegtekintések", - "pages": "Oldalak", "pageTitle": "Oldal címe", + "pages": "Oldalak", "paid-ads": "Fizetett hirdetések", "paid-search": "Fizetett keresés", "paid-shopping": "Fizetett vásárlás", @@ -225,7 +227,6 @@ "performance": "Teljesítmény", "pixel": "Pixel", "pixels": "Pixelek", - "play": "Lejátszás", "poor": "Gyenge", "powered-by": "Működteti az {name}", "preferences": "Beállítások", @@ -246,16 +247,16 @@ "referrers": "Hivatkozók", "refresh": "Frissítés", "regenerate": "Újragenerálás", - "regex-match": "Illeszkedik a reguláris kifejezésre", - "regex-not-match": "Nem illeszkedik a reguláris kifejezésre", "region": "Régió", "regions": "Régiók", "remaining": "Hátralévő", "remove": "Eltávolítás", "remove-member": "Tag eltávolítása", + "play": "Lejátszás", "replay": "Visszajátszás", - "replay-enabled": "Visszajátszás engedélyezve", "replay-id": "Replay ID", + "replay-code": "Munkamenet-újrajátszási kód", + "replay-enabled": "Visszajátszás engedélyezve", "replays": "Visszajátszások", "reports": "Jelentések", "required": "Kötelező", @@ -268,21 +269,24 @@ "revenue-description": "Tekintse meg bevételeit az idő múlásával.", "role": "Szerep", "run-query": "Lekérdezés futtatása", - "sample-rate": "Mintavételi arány", - "sample-size": "Mintaméret", "save": "Mentés", "save-cohort": "Kohorsz mentése", + "save-replay": "Újrajátszás mentése", "save-segment": "Szegmens mentése", + "sample-rate": "Mintavételi arány", + "sample-size": "Mintaméret", "screen": "Képernyő", "screens": "Képernyők", "search": "Keresés", "segment": "Szegmens", "segments": "Szegmensek", "select": "Kiválasztás", - "select-component": "Válasszon komponenst", + "select-link": "Hivatkozás kiválasztása", + "select-pixel": "Pixel kiválasztása", "select-date": "Dátum kiválasztása", "select-filter": "Szűrő kiválasztása", "select-role": "Szerep kiválasztása", + "select-component": "Válasszon komponenst", "select-website": "Weboldal kiválasztása", "session": "Munkamenet", "session-data": "Munkamenet adatai", @@ -337,9 +341,15 @@ "unique": "Egyedi", "unique-events": "Egyedi események", "unique-visitors": "Egyedi látogatók", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Egyedi ügyfelek", + "customers": "Ügyfelek", + "orders": "Rendelések", + "saved": "Mentve", "unknown": "Ismeretlen", "untitled": "Névtelen", + "upgrade": "Frissítés", "update": "Frissítés", "url": "URL", "user": "Felhasználó", @@ -379,8 +389,8 @@ "confirm-reset": "Are your sure you want to reset {target}'s statistics?", "delete-team-warning": "A csapat törlése az összes csapat weboldalt is törli.", "delete-website-warning": "Minden társított adat törlésre kerül.", - "empty-dashboard": "Az irányítópult üres. Kattintson a Szerkesztés gombra az első komponens hozzáadásához.", "error": "Valami baj történt.", + "empty-dashboard": "Az irányítópult üres. Kattintson a Szerkesztés gombra az első komponens hozzáadásához.", "event-log": "{event} itt: {url}", "forbidden": "Tiltott", "go-to-settings": "Tovább a beállításokhoz", @@ -402,6 +412,7 @@ "reset-website": "A weboldal visszaállításához írja be a(z) {confirmation} szót az alábbi mezőbe.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Sikeres mentés.", + "select-board-entity-first": "Először válasszon webhelyet, pixelt vagy hivatkozást.", "select-component-preview": "Válasszon egy komponenst az előnézethez", "select-website-first": "Először válasszon egy webhelyet", "sever-error": "Szerverhiba", @@ -417,6 +428,7 @@ "unauthorized": "Nincs jogosultság", "user-deleted": "Felhasználó törölve.", "viewed-page": "Megtekintett oldal", + "upgrade-required": "Ez a funkció {plan} előfizetést igényel.", "visitor-log": "Látógató {country} területéről, {os} {device} eszközön, {browser} böngészőből." } } diff --git a/public/intl/messages/id-ID.json b/public/intl/messages/id-ID.json index 99a95553a..1bc6b433c 100644 --- a/public/intl/messages/id-ID.json +++ b/public/intl/messages/id-ID.json @@ -20,10 +20,8 @@ "all-time": "Semua waktu", "analysis": "Analisis", "analytics": "Analitik", - "aov": "AOV", "application": "Aplikasi", "apply": "Terapkan", - "arpu": "ARPU", "attribution": "Atribusi", "attribution-description": "Lihat bagaimana pengguna berinteraksi dengan pemasaran Anda dan apa yang mendorong konversi.", "audience": "Audiens", @@ -33,6 +31,7 @@ "behavior": "Perilaku", "block-selector": "Pemilih blok", "boards": "Papan", + "board-type": "Jenis papan", "bounce-rate": "Rasio pentalan", "breakdown": "Rincian", "browser": "Peramban", @@ -55,6 +54,8 @@ "confirm": "Konfirmasi", "confirm-password": "Konfirmasi kata sandi", "contains": "Mengandung", + "regex-match": "Cocok dengan ekspresi reguler", + "regex-not-match": "Tidak cocok dengan ekspresi reguler", "content": "Konten", "continue": "Lanjutkan", "conversion": "Konversi", @@ -131,8 +132,8 @@ "funnels": "Corong", "goal": "Tujuan", "goals": "Tujuan", - "goals-description": "Lacak tujuan Anda untuk tampilan halaman dan peristiwa.", "good": "Baik", + "goals-description": "Lacak tujuan Anda untuk tampilan halaman dan peristiwa.", "greater-than": "Lebih dari", "greater-than-equals": "Lebih dari atau sama dengan", "grouped": "Dikelompokkan", @@ -140,10 +141,10 @@ "hostname": "Nama host", "hour": "Jam", "includes": "Termasuk", - "inp": "INP", "insight": "Wawasan", "insights": "Wawasan", "insights-description": "Jelajahi data Anda lebih dalam dengan menggunakan segmen dan filter.", + "inp": "INP", "invalid-url": "URL tidak valid", "is": "Adalah", "is-false": "Salah", @@ -177,11 +178,11 @@ "manage": "Kelola", "manager": "Manajer", "mask-level": "Tingkat masker", + "max": "Maksimum", + "max-duration": "Durasi maksimal", "match": "Cocok", "match-all": "Semua", "match-any": "Salah satu", - "max": "Maksimum", - "max-duration": "Durasi maksimal", "maximize": "Perluas", "medium": "Sedang", "member": "Anggota", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {catatan} other {catatan}}", "ok": "OK", "online": "Daring", + "open": "Campuran", "organic-search": "Pencarian organik", "organic-shopping": "Belanja organik", "organic-social": "Sosial organik", @@ -212,8 +214,8 @@ "page": "Halaman", "page-of": "Halaman {current} dari {total}", "page-views": "Tampilan halaman", - "pages": "Halaman", "pageTitle": "Judul halaman", + "pages": "Halaman", "paid-ads": "Iklan berbayar", "paid-search": "Pencarian berbayar", "paid-shopping": "Belanja berbayar", @@ -225,7 +227,6 @@ "performance": "Kinerja", "pixel": "Piksel", "pixels": "Piksel", - "play": "Putar", "poor": "Buruk", "powered-by": "Didukung oleh {name}", "preferences": "Preferensi", @@ -246,16 +247,16 @@ "referrers": "Perujuk", "refresh": "Segarkan", "regenerate": "Buat ulang", - "regex-match": "Cocok dengan ekspresi reguler", - "regex-not-match": "Tidak cocok dengan ekspresi reguler", "region": "Wilayah", "regions": "Wilayah", "remaining": "Tersisa", "remove": "Hapus", "remove-member": "Hapus anggota", + "play": "Putar", "replay": "Pemutaran ulang", - "replay-enabled": "Pemutaran ulang diaktifkan", "replay-id": "Replay ID", + "replay-code": "Kode putar ulang sesi", + "replay-enabled": "Pemutaran ulang diaktifkan", "replays": "Pemutaran ulang", "reports": "Laporan", "required": "Wajib", @@ -268,21 +269,24 @@ "revenue-description": "Lihat pendapatan Anda seiring waktu.", "role": "Peran", "run-query": "Jalankan kueri", - "sample-rate": "Laju sampel", - "sample-size": "Ukuran sampel", "save": "Simpan", "save-cohort": "Simpan kohort", + "save-replay": "Simpan putar ulang", "save-segment": "Simpan segmen", + "sample-rate": "Laju sampel", + "sample-size": "Ukuran sampel", "screen": "Layar", "screens": "Layar", "search": "Cari", "segment": "Segmen", "segments": "Segmen", "select": "Pilih", - "select-component": "Pilih komponen", + "select-link": "Pilih tautan", + "select-pixel": "Pilih piksel", "select-date": "Pilih tanggal", "select-filter": "Pilih filter", "select-role": "Pilih role", + "select-component": "Pilih komponen", "select-website": "Pilih situs web", "session": "Sesi", "session-data": "Data sesi", @@ -337,9 +341,15 @@ "unique": "Unik", "unique-events": "Event unik", "unique-visitors": "Pengunjung unik", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Kustomer unik", + "customers": "Pelanggan", + "orders": "Pesanan", + "saved": "Tersimpan", "unknown": "Tidak diketahui", "untitled": "Tanpa judul", + "upgrade": "Tingkatkan", "update": "Perbarui", "url": "URL", "user": "Pengguna", @@ -379,8 +389,8 @@ "confirm-reset": "Anda yakin ingin mengatur ulang statistik {target}?", "delete-team-warning": "Menghapus tim juga akan menghapus semua situs web yang terkait.", "delete-website-warning": "Semua data terkait juga akan dihapus.", - "empty-dashboard": "Dasbor Anda kosong. Klik Edit untuk menambahkan komponen pertama Anda.", "error": "Ada yang salah.", + "empty-dashboard": "Dasbor Anda kosong. Klik Edit untuk menambahkan komponen pertama Anda.", "event-log": "{event} di {url}", "forbidden": "Dilarang", "go-to-settings": "Pergi ke pengaturan", @@ -402,6 +412,7 @@ "reset-website": "Untuk mengatur ulang situs web ini, ketik {confirmation} pada kotak di bawah untuk mengonfirmasi.", "reset-website-warning": "Semua statistik pada situs web ini akan dihapus, tetapi kode lacak akan tetap terpasang", "saved": "Berhasil disimpan.", + "select-board-entity-first": "Pilih situs web, piksel, atau tautan terlebih dahulu.", "select-component-preview": "Pilih komponen untuk pratinjau", "select-website-first": "Pilih situs web terlebih dahulu", "sever-error": "Kesalahan server", @@ -417,6 +428,7 @@ "unauthorized": "Tidak diotorisasi", "user-deleted": "Pengguna telah dihapus.", "viewed-page": "Halaman dilihat", + "upgrade-required": "Fitur ini memerlukan langganan paket {plan}.", "visitor-log": "Pengunjung dari {country} dengan {browser} di {device} {os}" } } diff --git a/public/intl/messages/it-IT.json b/public/intl/messages/it-IT.json index 5f902f3e2..a4589faa7 100644 --- a/public/intl/messages/it-IT.json +++ b/public/intl/messages/it-IT.json @@ -20,10 +20,8 @@ "all-time": "Sempre", "analysis": "Analisi", "analytics": "Analitica", - "aov": "AOV", "application": "Applicazione", "apply": "Applica", - "arpu": "ARPU", "attribution": "Attribuzione", "attribution-description": "Scopri come gli utenti interagiscono con il tuo marketing e cosa genera conversioni.", "audience": "Pubblico", @@ -33,6 +31,7 @@ "behavior": "Comportamento", "block-selector": "Selettore di blocco", "boards": "Bacheche", + "board-type": "Tipo di bacheca", "bounce-rate": "Frequenza di rimbalzo", "breakdown": "Dettaglio", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Conferma", "confirm-password": "Conferma password", "contains": "Contiene", + "regex-match": "Corrisponde all'espressione regolare", + "regex-not-match": "Non corrisponde all'espressione regolare", "content": "Contenuto", "continue": "Continua", "conversion": "Conversione", @@ -131,8 +132,8 @@ "funnels": "Funnel", "goal": "Obiettivo", "goals": "Obiettivi", - "goals-description": "Tieni traccia dei tuoi obiettivi per visualizzazioni di pagina ed eventi.", "good": "Buono", + "goals-description": "Tieni traccia dei tuoi obiettivi per visualizzazioni di pagina ed eventi.", "greater-than": "Maggiore di", "greater-than-equals": "Maggiore o uguale a", "grouped": "Raggruppato", @@ -140,10 +141,10 @@ "hostname": "Nome host", "hour": "Ora", "includes": "Include", - "inp": "INP", "insight": "Approfondimento", "insights": "Approfondimenti", "insights-description": "Analizza più a fondo i tuoi dati utilizzando segmenti e filtri.", + "inp": "INP", "invalid-url": "URL non valido", "is": "È", "is-false": "È falso", @@ -177,11 +178,11 @@ "manage": "Gestisci", "manager": "Gestore", "mask-level": "Livello di maschera", + "max": "Massimo", + "max-duration": "Durata massima", "match": "Corrispondenza", "match-all": "Tutti", "match-any": "Qualsiasi", - "max": "Massimo", - "max-duration": "Durata massima", "maximize": "Espandi", "medium": "Medio", "member": "Membro", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {record} other {record}}", "ok": "OK", "online": "Online", + "open": "Misto", "organic-search": "Ricerca organica", "organic-shopping": "Acquisto organico", "organic-social": "Social organico", @@ -212,8 +214,8 @@ "page": "Pagina", "page-of": "Pagina {current} di {total}", "page-views": "Visualizzazioni di pagina", - "pages": "Pagine", "pageTitle": "Titolo pagina", + "pages": "Pagine", "paid-ads": "Annunci a pagamento", "paid-search": "Ricerca a pagamento", "paid-shopping": "Acquisto a pagamento", @@ -225,7 +227,6 @@ "performance": "Prestazioni", "pixel": "Pixel", "pixels": "Pixel", - "play": "Riproduci", "poor": "Scarso", "powered-by": "Fornito da {name}", "preferences": "Preferenze", @@ -246,16 +247,16 @@ "referrers": "Referenti", "refresh": "Ricarica", "regenerate": "Rigenera", - "regex-match": "Corrisponde all'espressione regolare", - "regex-not-match": "Non corrisponde all'espressione regolare", "region": "Regione", "regions": "Regioni", "remaining": "Rimanente", "remove": "Rimuovi", "remove-member": "Rimuovi membro", + "play": "Riproduci", "replay": "Replay", - "replay-enabled": "Replay abilitato", "replay-id": "Replay ID", + "replay-code": "Codice replay sessione", + "replay-enabled": "Replay abilitato", "replays": "Replay", "reports": "Report", "required": "Obbligatorio", @@ -268,21 +269,24 @@ "revenue-description": "Consulta i tuoi ricavi nel tempo.", "role": "Ruolo", "run-query": "Esegui query", - "sample-rate": "Frequenza di campionamento", - "sample-size": "Dimensione del campione", "save": "Salva", "save-cohort": "Salva coorte", + "save-replay": "Salva replay", "save-segment": "Salva segmento", + "sample-rate": "Frequenza di campionamento", + "sample-size": "Dimensione del campione", "screen": "Schermo", "screens": "Schermi", "search": "Cerca", "segment": "Segmento", "segments": "Segmenti", "select": "Seleziona", - "select-component": "Seleziona componente", + "select-link": "Seleziona link", + "select-pixel": "Seleziona pixel", "select-date": "Seleziona data", "select-filter": "Seleziona filtro", "select-role": "Seleziona ruolo", + "select-component": "Seleziona componente", "select-website": "Seleziona sito web", "session": "Sessione", "session-data": "Dati sessione", @@ -337,9 +341,15 @@ "unique": "Unico", "unique-events": "Eventi unici", "unique-visitors": "Visitatori unici", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clienti unici", + "customers": "Clienti", + "orders": "Ordini", + "saved": "Salvato", "unknown": "Sconosciuto", "untitled": "Senza titolo", + "upgrade": "Aggiorna", "update": "Aggiorna", "url": "URL", "user": "Utente", @@ -379,8 +389,8 @@ "confirm-reset": "Sei sicuro di voler azzerare le statistiche di {target}?", "delete-team-warning": "L'eliminazione di un team eliminerà anche tutti i siti web del team.", "delete-website-warning": "Saranno eliminati anche tutti i dati associati.", - "empty-dashboard": "La tua dashboard è vuota. Fai clic su Modifica per aggiungere il tuo primo componente.", "error": "Si è verificato un errore.", + "empty-dashboard": "La tua dashboard è vuota. Fai clic su Modifica per aggiungere il tuo primo componente.", "event-log": "{event} su {url}", "forbidden": "Vietato", "go-to-settings": "Vai alle impostazioni", @@ -402,6 +412,7 @@ "reset-website": "Per reimpostare questo sito web, digita {confirmation} nella casella sottostante per confermare.", "reset-website-warning": "Tutte le statistiche verranno cancellate per questo sito, ma il tuo codice di tracciamento rimarrà invariato.", "saved": "Salvato!", + "select-board-entity-first": "Seleziona prima un sito web, pixel o link.", "select-component-preview": "Seleziona un componente per l'anteprima", "select-website-first": "Seleziona prima un sito web", "sever-error": "Errore del server", @@ -417,6 +428,7 @@ "unauthorized": "Non autorizzato", "user-deleted": "Utente eliminato.", "viewed-page": "Pagina visualizzata", + "upgrade-required": "Questa funzionalità richiede un abbonamento al piano {plan}.", "visitor-log": "Utenti da {country} tramite {browser} su {os} {device}" } } diff --git a/public/intl/messages/lt-LT.json b/public/intl/messages/lt-LT.json index 9a9a7c92b..c0b2aaa0c 100644 --- a/public/intl/messages/lt-LT.json +++ b/public/intl/messages/lt-LT.json @@ -20,10 +20,8 @@ "all-time": "Visas laikotarpis", "analysis": "Analizė", "analytics": "Analitika", - "aov": "AOV", "application": "Programėlė", "apply": "Taikyti", - "arpu": "ARPU", "attribution": "Priskyrimas", "attribution-description": "Žiūrėkite, kaip naudotojai įsitraukia į jūsų rinkodarą ir kas lemia konversijas.", "audience": "Auditorija", @@ -33,6 +31,7 @@ "behavior": "Elgsena", "block-selector": "Bloko pasirinkiklis", "boards": "Lentos", + "board-type": "Skydelio tipas", "bounce-rate": "Atmetimo rodiklis", "breakdown": "Išskaidymas", "browser": "Naršyklė", @@ -55,6 +54,8 @@ "confirm": "Patvirtinti", "confirm-password": "Patvirtinti slaptažodį", "contains": "Turi", + "regex-match": "Atitinka reguliariąją išraišką", + "regex-not-match": "Neatitinka reguliariosios išraiškos", "content": "Turinys", "continue": "Tęsti", "conversion": "Konversija", @@ -131,8 +132,8 @@ "funnels": "Piltuvai", "goal": "Tikslas", "goals": "Tikslai", - "goals-description": "Sekite savo tikslus puslapių peržiūroms ir įvykiams.", "good": "Gerai", + "goals-description": "Sekite savo tikslus puslapių peržiūroms ir įvykiams.", "greater-than": "Daugiau nei", "greater-than-equals": "Daugiau arba lygu", "grouped": "Grupuota", @@ -140,10 +141,10 @@ "hostname": "Pagrindinis kompiuteris", "hour": "Valanda", "includes": "Įtraukia", - "inp": "INP", "insight": "Įžvalga", "insights": "Įžvalgos", "insights-description": "Pasinerkite giliau į savo duomenis naudodami segmentus ir filtrus.", + "inp": "INP", "invalid-url": "Netinkamas URL", "is": "Yra", "is-false": "Yra netiesa", @@ -177,11 +178,11 @@ "manage": "Tvarkyti", "manager": "Vadovas", "mask-level": "Maskavimo lygis", + "max": "Maksimumas", + "max-duration": "Maksimali trukmė", "match": "Atitikimas", "match-all": "Visi", "match-any": "Bet kuris", - "max": "Maksimumas", - "max-duration": "Maksimali trukmė", "maximize": "Išplėsti", "medium": "Vidutinis", "member": "Narys", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {įrašas} few {įrašai} other {įrašų}}", "ok": "Gerai", "online": "Prisijungęs", + "open": "Mišrus", "organic-search": "Organinė paieška", "organic-shopping": "Organinis apsipirkimas", "organic-social": "Organinis socialinis", @@ -212,8 +214,8 @@ "page": "Puslapis", "page-of": "Puslapis {current} iš {total}", "page-views": "Puslapių peržiūros", - "pages": "Puslapiai", "pageTitle": "Puslapio pavadinimas", + "pages": "Puslapiai", "paid-ads": "Mokama reklama", "paid-search": "Mokama paieška", "paid-shopping": "Mokamas apsipirkimas", @@ -225,7 +227,6 @@ "performance": "Veikimas", "pixel": "Pikselis", "pixels": "Pikseliai", - "play": "Leisti", "poor": "Blogai", "powered-by": "Teikia {name}", "preferences": "Nuostatos", @@ -246,16 +247,16 @@ "referrers": "Persiuntėjai", "refresh": "Atnaujinti", "regenerate": "Sugeneruoti iš naujo", - "regex-match": "Atitinka reguliariąją išraišką", - "regex-not-match": "Neatitinka reguliariosios išraiškos", "region": "Regionas", "regions": "Regionai", "remaining": "Likę", "remove": "Pašalinti", "remove-member": "Pašalinti narį", + "play": "Leisti", "replay": "Pakartojimas", - "replay-enabled": "Pakartojimas įjungtas", "replay-id": "Replay ID", + "replay-code": "Sesijos pakartojimo kodas", + "replay-enabled": "Pakartojimas įjungtas", "replays": "Pakartojimai", "reports": "Ataskaitos", "required": "Reikalinga", @@ -268,21 +269,24 @@ "revenue-description": "Peržiūrėkite savo pajamas laikui bėgant.", "role": "Vaidmuo", "run-query": "Vykdyti užklausą", - "sample-rate": "Imties dažnis", - "sample-size": "Imties dydis", "save": "Išsaugoti", "save-cohort": "Išsaugoti kohortą", + "save-replay": "Išsaugoti pakartojimą", "save-segment": "Išsaugoti segmentą", + "sample-rate": "Imties dažnis", + "sample-size": "Imties dydis", "screen": "Ekranas", "screens": "Ekranai", "search": "Ieškoti", "segment": "Segmentas", "segments": "Segmentai", "select": "Pasirinkti", - "select-component": "Pasirinkite komponentą", + "select-link": "Pasirinkti nuorodą", + "select-pixel": "Pasirinkti pikselį", "select-date": "Pasirinkti laikotarpį", "select-filter": "Pasirinkti filtrą", "select-role": "Pasirinkti rolę", + "select-component": "Pasirinkite komponentą", "select-website": "Pasirinkti svetainę", "session": "Sesija", "session-data": "Sesijos duomenys", @@ -337,9 +341,15 @@ "unique": "Unikalūs", "unique-events": "Unikalūs įvykiai", "unique-visitors": "Unikalūs lankytojai", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unikalūs klientai", + "customers": "Klientai", + "orders": "Užsakymai", + "saved": "Išsaugota", "unknown": "Nežinoma", "untitled": "Be pavadinimo", + "upgrade": "Atnaujinti", "update": "Atnaujinti", "url": "URL", "user": "Vartotojas", @@ -379,8 +389,8 @@ "confirm-reset": "Are esate tikri, jog norite atstatyti svetainės {target} statistikos duomenis?", "delete-team-warning": "Ištrinant komandą bus ištrintos ir visos komandos svetainės.", "delete-website-warning": "Visi susiję duomenys taip pat bus ištrinti.", - "empty-dashboard": "Jūsų prietaisų skydelis tuščias. Spustelėkite Redaguoti, kad pridėtumėte pirmąjį komponentą.", "error": "Kažkas įvyko ne taip.", + "empty-dashboard": "Jūsų prietaisų skydelis tuščias. Spustelėkite Redaguoti, kad pridėtumėte pirmąjį komponentą.", "event-log": "{event} puslapyje {url}", "forbidden": "Draudžiama", "go-to-settings": "Eiti į nustatymus", @@ -402,6 +412,7 @@ "reset-website": "Kad atstatyti šią svetainę, įrašykite {confirmation} žemiau, kad patvirtintumėte.", "reset-website-warning": "Visi šios svetainės statistikos duomenys bus ištrinti, bet sekimo kodas išliks nepaliestas.", "saved": "Sėkmingai išsaugota.", + "select-board-entity-first": "Pirmiausia pasirinkite svetainę, pikselį arba nuorodą.", "select-component-preview": "Pasirinkite komponentą peržiūrai", "select-website-first": "Pirmiausia pasirinkite svetainę", "sever-error": "Serverio klaida", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizuota", "user-deleted": "Vartotojas ištrintas.", "viewed-page": "Peržiūrėtas puslapis", + "upgrade-required": "Šiai funkcijai reikalinga {plan} plano prenumerata.", "visitor-log": "Lankytojas iš {country}, naudojantis {browser} sistemoje {os} {device}" } } diff --git a/public/intl/messages/ms-MY.json b/public/intl/messages/ms-MY.json index 7d1db53f6..d34510f54 100644 --- a/public/intl/messages/ms-MY.json +++ b/public/intl/messages/ms-MY.json @@ -20,10 +20,8 @@ "all-time": "Sepanjang masa", "analysis": "Analisis", "analytics": "Analitik", - "aov": "AOV", "application": "Aplikasi", "apply": "Terapkan", - "arpu": "ARPU", "attribution": "Atribusi", "attribution-description": "Lihat bagaimana pengguna berinteraksi dengan pemasaran anda dan apa yang mendorong penukaran.", "audience": "Khalayak", @@ -33,6 +31,7 @@ "behavior": "Tingkah laku", "block-selector": "Pemilih blok", "boards": "Papan", + "board-type": "Jenis papan", "bounce-rate": "Kadar lantunan", "breakdown": "Pecahan", "browser": "Pelayar", @@ -55,6 +54,8 @@ "confirm": "Sahkan", "confirm-password": "Sahkan kata laluan", "contains": "Mengandungi", + "regex-match": "Sepadan dengan ungkapan biasa", + "regex-not-match": "Tidak sepadan dengan ungkapan biasa", "content": "Kandungan", "continue": "Teruskan", "conversion": "Penukaran", @@ -131,8 +132,8 @@ "funnels": "Corong", "goal": "Matlamat", "goals": "Matlamat", - "goals-description": "Jejaki matlamat anda untuk paparan halaman dan peristiwa.", "good": "Baik", + "goals-description": "Jejaki matlamat anda untuk paparan halaman dan peristiwa.", "greater-than": "Lebih besar dari", "greater-than-equals": "Lebih besar atau sama", "grouped": "Dikumpulkan", @@ -140,10 +141,10 @@ "hostname": "Nama hos", "hour": "Jam", "includes": "Termasuk", - "inp": "INP", "insight": "Wawasan", "insights": "Wawasan", "insights-description": "Terokai data anda dengan lebih mendalam menggunakan segmen dan tapis.", + "inp": "INP", "invalid-url": "URL tidak sah", "is": "Adalah", "is-false": "Adalah palsu", @@ -177,11 +178,11 @@ "manage": "Urus", "manager": "Pengurus", "mask-level": "Tahap pelindung", + "max": "Maks", + "max-duration": "Tempoh maksimum", "match": "Padanan", "match-all": "Semua", "match-any": "Mana-mana", - "max": "Maks", - "max-duration": "Tempoh maksimum", "maximize": "Expand", "medium": "Medium", "member": "Ahli", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {rekod} other {rekod}}", "ok": "OK", "online": "Dalam talian", + "open": "Campuran", "organic-search": "Carian organik", "organic-shopping": "Beli-belah organik", "organic-social": "Sosial organik", @@ -212,8 +214,8 @@ "page": "Halaman", "page-of": "Halaman {current} daripada {total}", "page-views": "Paparan halaman", - "pages": "Halaman", "pageTitle": "Tajuk halaman", + "pages": "Halaman", "paid-ads": "Iklan berbayar", "paid-search": "Carian berbayar", "paid-shopping": "Beli-belah berbayar", @@ -225,7 +227,6 @@ "performance": "Prestasi", "pixel": "Piksel", "pixels": "Piksel", - "play": "Main", "poor": "Lemah", "powered-by": "Disediakan oleh {name}", "preferences": "Keutamaan", @@ -246,16 +247,16 @@ "referrers": "Perujuk", "refresh": "Muat semula", "regenerate": "Jana semula", - "regex-match": "Sepadan dengan ungkapan biasa", - "regex-not-match": "Tidak sepadan dengan ungkapan biasa", "region": "Wilayah", "regions": "Wilayah", "remaining": "Baki", "remove": "Buang", "remove-member": "Buang ahli", + "play": "Main", "replay": "Main semula", - "replay-enabled": "Main semula diaktifkan", "replay-id": "Replay ID", + "replay-code": "Kod main semula sesi", + "replay-enabled": "Main semula diaktifkan", "replays": "Main semula", "reports": "Laporan", "required": "Diperlukan", @@ -268,21 +269,24 @@ "revenue-description": "Look into your revenue across time.", "role": "Peranan", "run-query": "Jalankan pertanyaan", - "sample-rate": "Kadar pensampelan", - "sample-size": "Saiz sampel", "save": "Simpan", "save-cohort": "Simpan kohort", + "save-replay": "Simpan main semula", "save-segment": "Simpan segmen", + "sample-rate": "Kadar pensampelan", + "sample-size": "Saiz sampel", "screen": "Skrin", "screens": "Skrin", "search": "Cari", "segment": "Segmen", "segments": "Segmen", "select": "Pilih", - "select-component": "Pilih komponen", + "select-link": "Pilih pautan", + "select-pixel": "Pilih piksel", "select-date": "Pilih tarikh", "select-filter": "Pilih tapis", "select-role": "Pilih peranan", + "select-component": "Pilih komponen", "select-website": "Pilih laman web", "session": "Sesi", "session-data": "Data sesi", @@ -337,9 +341,15 @@ "unique": "Unik", "unique-events": "Peristiwa unik", "unique-visitors": "Pelawat unik", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Pelanggan unik", + "customers": "Pelanggan", + "orders": "Pesanan", + "saved": "Disimpan", "unknown": "Tidak diketahui", "untitled": "Tanpa tajuk", + "upgrade": "Naik taraf", "update": "Kemas kini", "url": "URL", "user": "Pengguna", @@ -379,8 +389,8 @@ "confirm-reset": "Are your sure you want to reset {target}'s statistics?", "delete-team-warning": "Memadamkan pasukan juga akan memadamkan semua laman web pasukan.", "delete-website-warning": "Semua data yang berkaitan juga akan dihapuskan.", - "empty-dashboard": "Papan pemuka anda kosong. Klik Edit untuk menambah komponen pertama anda.", "error": "Ada yang tidak kena.", + "empty-dashboard": "Papan pemuka anda kosong. Klik Edit untuk menambah komponen pertama anda.", "event-log": "{event} di {url}", "forbidden": "Dilarang", "go-to-settings": "Pergi ke tetapan", @@ -402,6 +412,7 @@ "reset-website": "Untuk menetapkan semula laman web ini, taip {confirmation} dalam kotak di bawah.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Berjaya disimpan.", + "select-board-entity-first": "Pilih laman web, piksel, atau pautan terlebih dahulu.", "select-component-preview": "Pilih komponen untuk pratonton", "select-website-first": "Pilih laman web dahulu", "sever-error": "Ralat pelayan", @@ -417,6 +428,7 @@ "unauthorized": "Tidak dibenarkan", "user-deleted": "Pengguna dipadamkan.", "viewed-page": "Halaman dilihat", + "upgrade-required": "Ciri ini memerlukan langganan pelan {plan}.", "visitor-log": "Pelawat dari {country} mengguna {browser} pada {os} {device}" } } diff --git a/public/intl/messages/nb-NO.json b/public/intl/messages/nb-NO.json index e79a813ad..699500727 100644 --- a/public/intl/messages/nb-NO.json +++ b/public/intl/messages/nb-NO.json @@ -20,10 +20,8 @@ "all-time": "Noensinne", "analysis": "Analyse", "analytics": "Analyse", - "aov": "AOV", "application": "Applikasjon", "apply": "Bruk", - "arpu": "ARPU", "attribution": "Attribusjon", "attribution-description": "Se hvordan brukere engasjerer seg i markedsføringen din og hva som driver konverteringer.", "audience": "Målgruppe", @@ -33,6 +31,7 @@ "behavior": "Atferd", "block-selector": "Blokkvelger", "boards": "Tavler", + "board-type": "Tavletype", "bounce-rate": "Avvisningsfrekvens", "breakdown": "Nedbrytning", "browser": "Nettleser", @@ -55,6 +54,8 @@ "confirm": "Bekreft", "confirm-password": "Godkjenn passord", "contains": "Inneholder", + "regex-match": "Samsvarer med regulært uttrykk", + "regex-not-match": "Samsvarer ikke med regulært uttrykk", "content": "Innhold", "continue": "Fortsett", "conversion": "Konvertering", @@ -131,8 +132,8 @@ "funnels": "Trakter", "goal": "Mål", "goals": "Mål", - "goals-description": "Spor dine mål for sidevisninger og hendelser.", "good": "God", + "goals-description": "Spor dine mål for sidevisninger og hendelser.", "greater-than": "Mer enn", "greater-than-equals": "Mer enn eller lik", "grouped": "Gruppert", @@ -140,10 +141,10 @@ "hostname": "Vertsnavn", "hour": "Time", "includes": "Inkluderer", - "inp": "INP", "insight": "Innsikt", "insights": "Innsikt", "insights-description": "Dykk dypere i din data ved bruk av segmentering og filtre.", + "inp": "INP", "invalid-url": "Ugyldig URL", "is": "Er", "is-false": "Er usant", @@ -177,11 +178,11 @@ "manage": "Administrer", "manager": "Administrator", "mask-level": "Maskenivå", + "max": "Maks", + "max-duration": "Maksimal varighet", "match": "Samsvar", "match-all": "Alle", "match-any": "Enhver", - "max": "Maks", - "max-duration": "Maksimal varighet", "maximize": "Utvid", "medium": "Medium", "member": "Bruker", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {post} other {poster}}", "ok": "OK", "online": "Tilkoblet", + "open": "Blandet", "organic-search": "Organisk søk", "organic-shopping": "Organisk handel", "organic-social": "Organisk sosial", @@ -212,8 +214,8 @@ "page": "Side", "page-of": "Side {current} av {total}", "page-views": "Sidevisninger", - "pages": "Sider", "pageTitle": "Sidetittel", + "pages": "Sider", "paid-ads": "Betalte annonser", "paid-search": "Betalt søk", "paid-shopping": "Betalt handel", @@ -225,7 +227,6 @@ "performance": "Ytelse", "pixel": "Piksel", "pixels": "Piksler", - "play": "Spill av", "poor": "Dårlig", "powered-by": "Drevet av {name}", "preferences": "Innstillinger", @@ -246,16 +247,16 @@ "referrers": "Henvisere", "refresh": "Oppdater", "regenerate": "Regenerer", - "regex-match": "Samsvarer med regulært uttrykk", - "regex-not-match": "Samsvarer ikke med regulært uttrykk", "region": "Region", "regions": "Regioner", "remaining": "Gjenstår", "remove": "Fjern", "remove-member": "Fjern bruker", + "play": "Spill av", "replay": "Avspilling", - "replay-enabled": "Avspilling aktivert", "replay-id": "Replay ID", + "replay-code": "Kode for øktavspilling", + "replay-enabled": "Avspilling aktivert", "replays": "Avspillinger", "reports": "Rapporter", "required": "Påkrevd", @@ -268,21 +269,24 @@ "revenue-description": "Se på inntektene dine over tid.", "role": "Rolle", "run-query": "Kjør spørring", - "sample-rate": "Samplingsfrekvens", - "sample-size": "Utvalgsstørrelse", "save": "Lagre", "save-cohort": "Lagre kohort", + "save-replay": "Lagre avspilling", "save-segment": "Lagre segment", + "sample-rate": "Samplingsfrekvens", + "sample-size": "Utvalgsstørrelse", "screen": "Skjerm", "screens": "Skjermer", "search": "Søk", "segment": "Segment", "segments": "Segmenter", "select": "Velg", - "select-component": "Velg komponent", + "select-link": "Velg lenke", + "select-pixel": "Velg piksel", "select-date": "Velg dato", "select-filter": "Velg filter", "select-role": "Velg rolle", + "select-component": "Velg komponent", "select-website": "Velg nettsted", "session": "Økt", "session-data": "Øktdata", @@ -337,9 +341,15 @@ "unique": "Unike", "unique-events": "Unike hendelser", "unique-visitors": "Unike besøkende", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unike kunder", + "customers": "Kunder", + "orders": "Bestillinger", + "saved": "Lagret", "unknown": "Ukjent", "untitled": "Uten tittel", + "upgrade": "Oppgrader", "update": "Oppdater", "url": "URL", "user": "Bruker", @@ -379,8 +389,8 @@ "confirm-reset": "Er du sikker på at du vil nullstille statistikken til {target}?", "delete-team-warning": "Å slette et team vil også slette alle teamets nettsteder.", "delete-website-warning": "Alle tilknyttede data vil også bli slettet.", - "empty-dashboard": "Dashbordet ditt er tomt. Klikk Rediger for å legge til din første komponent.", "error": "Noe gikk galt.", + "empty-dashboard": "Dashbordet ditt er tomt. Klikk Rediger for å legge til din første komponent.", "event-log": "{event}{url}", "forbidden": "Forbudt", "go-to-settings": "Gå til innstillinger", @@ -402,6 +412,7 @@ "reset-website": "For å nullstille dette nettstedet, skriv {confirmation} i feltet nedenfor for å bekrefte.", "reset-website-warning": "All statistikk for dette nettstedet vil bli slettet, men sporingskoden forblir uberørt.", "saved": "Lagret!", + "select-board-entity-first": "Velg først et nettsted, piksel eller lenke.", "select-component-preview": "Velg en komponent for forhåndsvisning", "select-website-first": "Velg et nettsted først", "sever-error": "Serverfeil", @@ -417,6 +428,7 @@ "unauthorized": "Ikke autorisert", "user-deleted": "Bruker slettet.", "viewed-page": "Vist side", + "upgrade-required": "Denne funksjonen krever et {plan}-abonnement.", "visitor-log": "Besøkende fra {country} med {browser}{os} {device}" } } diff --git a/public/intl/messages/nl-NL.json b/public/intl/messages/nl-NL.json index 8c617dab7..0749ac70e 100644 --- a/public/intl/messages/nl-NL.json +++ b/public/intl/messages/nl-NL.json @@ -20,10 +20,8 @@ "all-time": "Onbeperkt", "analysis": "Analyse", "analytics": "Analyse", - "aov": "AOV", "application": "Applicatie", "apply": "Toepassen", - "arpu": "ARPU", "attribution": "Toewijzing", "attribution-description": "Bekijk hoe gebruikers omgaan met je marketing en wat conversies stimuleert.", "audience": "Publiek", @@ -33,6 +31,7 @@ "behavior": "Gedrag", "block-selector": "Blokselectie", "boards": "Borden", + "board-type": "Bordtype", "bounce-rate": "Bouncepercentage", "breakdown": "Opsplitsen", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Bevestigen", "confirm-password": "Wachtwoord bevestigen", "contains": "Bevat", + "regex-match": "Komt overeen met reguliere expressie", + "regex-not-match": "Komt niet overeen met reguliere expressie", "content": "Inhoud", "continue": "Doorgaan", "conversion": "Conversie", @@ -131,8 +132,8 @@ "funnels": "Trechters", "goal": "Doel", "goals": "Doelen", - "goals-description": "Volg je doelen voor paginaweergaven en gebeurtenissen.", "good": "Goed", + "goals-description": "Volg je doelen voor paginaweergaven en gebeurtenissen.", "greater-than": "Groter dan", "greater-than-equals": "Groter of gelijk aan", "grouped": "Gegroepeerd", @@ -140,10 +141,10 @@ "hostname": "Hostnaam", "hour": "Uur", "includes": "Bevat", - "inp": "INP", "insight": "Inzicht", "insights": "Inzichten", "insights-description": "Verken je gegevens verder door segmenten en filters te gebruiken.", + "inp": "INP", "invalid-url": "Ongeldige URL", "is": "Is", "is-false": "Is onwaar", @@ -177,11 +178,11 @@ "manage": "Beheren", "manager": "Beheerder", "mask-level": "Maskeerniveau", + "max": "Max", + "max-duration": "Maximale duur", "match": "Overeenkomst", "match-all": "Alle", "match-any": "Elk", - "max": "Max", - "max-duration": "Maximale duur", "maximize": "Uitvouwen", "medium": "Medium", "member": "Gebruiker", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {record} other {records}}", "ok": "OK", "online": "Online", + "open": "Gemengd", "organic-search": "Organisch zoeken", "organic-shopping": "Organisch winkelen", "organic-social": "Organisch sociaal", @@ -212,8 +214,8 @@ "page": "Pagina", "page-of": "Pagina {current} van {total}", "page-views": "Paginaweergaven", - "pages": "Pagina's", "pageTitle": "Pagina titel", + "pages": "Pagina's", "paid-ads": "Betaalde advertenties", "paid-search": "Betaald zoeken", "paid-shopping": "Betaald winkelen", @@ -225,7 +227,6 @@ "performance": "Prestaties", "pixel": "Pixel", "pixels": "Pixels", - "play": "Afspelen", "poor": "Slecht", "powered-by": "mogelijk gemaakt door {name}", "preferences": "Voorkeuren", @@ -246,16 +247,16 @@ "referrers": "Verwijzers", "refresh": "Vernieuwen", "regenerate": "Opnieuw genereren", - "regex-match": "Komt overeen met reguliere expressie", - "regex-not-match": "Komt niet overeen met reguliere expressie", "region": "Regio", "regions": "Regio's", "remaining": "Resterend", "remove": "Verwijderen", "remove-member": "Gebruiker verwijderen", + "play": "Afspelen", "replay": "Herhaling", - "replay-enabled": "Herhaling ingeschakeld", "replay-id": "Replay ID", + "replay-code": "Sessieherhalingscode", + "replay-enabled": "Herhaling ingeschakeld", "replays": "Herhalingen", "reports": "Rapporten", "required": "Verplicht", @@ -268,21 +269,24 @@ "revenue-description": "Bekijk je omzet in de loop van de tijd.", "role": "Gebruikersrol", "run-query": "Query uitvoeren", - "sample-rate": "Bemonsteringsfrequentie", - "sample-size": "Steekproefgrootte", "save": "Opslaan", "save-cohort": "Cohort opslaan", + "save-replay": "Herhaling opslaan", "save-segment": "Segment opslaan", + "sample-rate": "Bemonsteringsfrequentie", + "sample-size": "Steekproefgrootte", "screen": "Scherm", "screens": "Schermen", "search": "Zoeken", "segment": "Segment", "segments": "Segmenten", "select": "Selecteer", - "select-component": "Component selecteren", + "select-link": "Link selecteren", + "select-pixel": "Pixel selecteren", "select-date": "Datum selecteren", "select-filter": "Filter selecteren", "select-role": "Rol selecteren", + "select-component": "Component selecteren", "select-website": "Website selecteren", "session": "Sessie", "session-data": "Sessiegegevens", @@ -337,9 +341,15 @@ "unique": "Uniek", "unique-events": "Unieke gebeurtenissen", "unique-visitors": "Unieke bezoekers", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unieke klanten", + "customers": "Klanten", + "orders": "Bestellingen", + "saved": "Opgeslagen", "unknown": "Onbekend", "untitled": "Ongetiteld", + "upgrade": "Upgraden", "update": "Bijwerken", "url": "URL", "user": "Gebruiker", @@ -379,8 +389,8 @@ "confirm-reset": "Weet je zeker dat je de statistieken van {target} opnieuw wilt instellen?", "delete-team-warning": "Als een team wordt verwijderd, worden ook alle websites van dat team verwijderd.", "delete-website-warning": "Alle verwante gegevens zullen ook verwijderd worden.", - "empty-dashboard": "Uw dashboard is leeg. Klik op Bewerken om uw eerste component toe te voegen.", "error": "Er is iets misgegaan.", + "empty-dashboard": "Uw dashboard is leeg. Klik op Bewerken om uw eerste component toe te voegen.", "event-log": "{event} op {url}", "forbidden": "Verboden", "go-to-settings": "Naar instellingen", @@ -402,6 +412,7 @@ "reset-website": "Typ {confirmation} in het veld hieronder om te bevestigen dat je de website wilt resetten.", "reset-website-warning": "Alle bijhorende statistieken van deze website worden verwijderd, maar jouw volgcode blijft gelden.", "saved": "Opslaan succesvol.", + "select-board-entity-first": "Selecteer eerst een website, pixel of link.", "select-component-preview": "Selecteer een component voor een voorvertoning", "select-website-first": "Selecteer eerst een website", "sever-error": "Serverfout", @@ -417,6 +428,7 @@ "unauthorized": "Niet geautoriseerd", "user-deleted": "Gebruiker verwijderd", "viewed-page": "Bekeken pagina", + "upgrade-required": "Deze functie vereist een {plan}-abonnement.", "visitor-log": "Bezoeker uit {country} met {browser} op een {os} {device}" } } diff --git a/public/intl/messages/pl-PL.json b/public/intl/messages/pl-PL.json index 7803fcd38..ff3051a38 100644 --- a/public/intl/messages/pl-PL.json +++ b/public/intl/messages/pl-PL.json @@ -20,10 +20,8 @@ "all-time": "Cały czas", "analysis": "Analiza", "analytics": "Analityka", - "aov": "AOV", "application": "Aplikacja", "apply": "Zastosuj", - "arpu": "ARPU", "attribution": "Atrybucja", "attribution-description": "Zobacz, jak użytkownicy angażują się w Twoją reklamę i co napędza konwersje.", "audience": "Odbiorcy", @@ -33,6 +31,7 @@ "behavior": "Zachowanie", "block-selector": "Selektor bloków", "boards": "Tablice", + "board-type": "Typ tablicy", "bounce-rate": "Współczynnik odrzuceń", "breakdown": "Rozbicie", "browser": "Przeglądarka", @@ -55,6 +54,8 @@ "confirm": "Potwierdź", "confirm-password": "Potwierdź hasło", "contains": "Zawiera", + "regex-match": "Pasuje do wyrażenia regularnego", + "regex-not-match": "Nie pasuje do wyrażenia regularnego", "content": "Treść", "continue": "Kontynuuj", "conversion": "Konwersja", @@ -131,8 +132,8 @@ "funnels": "Lejki", "goal": "Cel", "goals": "Cele", - "goals-description": "Śledź cele dla odsłon stron i zdarzeń.", "good": "Dobrze", + "goals-description": "Śledź cele dla odsłon stron i zdarzeń.", "greater-than": "Większe niż", "greater-than-equals": "Większe niż lub równe", "grouped": "Grupowane", @@ -140,10 +141,10 @@ "hostname": "Nazwa hosta", "hour": "Godzina", "includes": "Zawiera", - "inp": "INP", "insight": "Wgląd", "insights": "Analiza", "insights-description": "Poznaj lepiej swoje dane, korzystając z segmentów i filtrów.", + "inp": "INP", "invalid-url": "Nieprawidłowy URL", "is": "Równe", "is-false": "Jest fałszem", @@ -177,11 +178,11 @@ "manage": "Zarządzaj", "manager": "Menedżer", "mask-level": "Poziom maski", + "max": "Maks", + "max-duration": "Maksymalny czas trwania", "match": "Dopasowanie", "match-all": "Wszystkie", "match-any": "Dowolny", - "max": "Maks", - "max-duration": "Maksymalny czas trwania", "maximize": "Rozwiń", "medium": "Medium", "member": "Członek", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {rekord} other {rekordy}}", "ok": "OK", "online": "Online", + "open": "Mieszany", "organic-search": "Wyszukiwanie organiczne", "organic-shopping": "Zakupy organiczne", "organic-social": "Organiczne social media", @@ -212,8 +214,8 @@ "page": "Strona", "page-of": "Strona {current} z {total}", "page-views": "Wyświetlenia strony", - "pages": "Strony", "pageTitle": "Tytuł strony", + "pages": "Strony", "paid-ads": "Reklamy płatne", "paid-search": "Płatne wyszukiwanie", "paid-shopping": "Płatne zakupy", @@ -225,7 +227,6 @@ "performance": "Wydajność", "pixel": "Piksel", "pixels": "Piksele", - "play": "Odtwórz", "poor": "Słabo", "powered-by": "Obsługiwane przez {name}", "preferences": "Preferencje", @@ -246,16 +247,16 @@ "referrers": "Źródła odsyłające", "refresh": "Odśwież", "regenerate": "Wygeneruj ponownie", - "regex-match": "Pasuje do wyrażenia regularnego", - "regex-not-match": "Nie pasuje do wyrażenia regularnego", "region": "Region", "regions": "Regiony", "remaining": "Pozostało", "remove": "Usuń", "remove-member": "Usuń członka", + "play": "Odtwórz", "replay": "Odtwarzanie", - "replay-enabled": "Odtwarzanie włączone", "replay-id": "Replay ID", + "replay-code": "Kod odtworzenia sesji", + "replay-enabled": "Odtwarzanie włączone", "replays": "Odtwarzania", "reports": "Raporty", "required": "Wymagany", @@ -268,21 +269,24 @@ "revenue-description": "Sprawdź swoje przychody w czasie.", "role": "Rola", "run-query": "Uruchom zapytanie", - "sample-rate": "Częstotliwość próbkowania", - "sample-size": "Rozmiar próbki", "save": "Zapisz", "save-cohort": "Zapisz kohortę", + "save-replay": "Zapisz odtworzenie", "save-segment": "Zapisz segment", + "sample-rate": "Częstotliwość próbkowania", + "sample-size": "Rozmiar próbki", "screen": "Ekran", "screens": "Ekrany", "search": "Szukaj", "segment": "Segment", "segments": "Segmenty", "select": "Wybierz", - "select-component": "Wybierz komponent", + "select-link": "Wybierz link", + "select-pixel": "Wybierz piksel", "select-date": "Wybierz datę", "select-filter": "Wybierz filtr", "select-role": "Wybierz rolę", + "select-component": "Wybierz komponent", "select-website": "Wybierz witrynę", "session": "Sesja", "session-data": "Dane sesji", @@ -337,9 +341,15 @@ "unique": "Unikalne", "unique-events": "Unikalne zdarzenia", "unique-visitors": "Unikalni odwiedzający", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unikalni klienci", + "customers": "Klienci", + "orders": "Zamówienia", + "saved": "Zapisano", "unknown": "Nieznany", "untitled": "Bez tytułu", + "upgrade": "Ulepsz", "update": "Aktualizuj", "url": "URL", "user": "Użytkownik", @@ -379,8 +389,8 @@ "confirm-reset": "Czy na pewno chcesz zresetować statystyki {target}?", "delete-team-warning": "Usunięcie zespołu usunie wszystkie jego witryny.", "delete-website-warning": "Wszystkie powiązane dane również zostaną usunięte.", - "empty-dashboard": "Twój pulpit jest pusty. Kliknij Edytuj, aby dodać pierwszy komponent.", "error": "Coś poszło nie tak.", + "empty-dashboard": "Twój pulpit jest pusty. Kliknij Edytuj, aby dodać pierwszy komponent.", "event-log": "{event} na {url}", "forbidden": "Zabronione", "go-to-settings": "Przejdź do ustawień", @@ -402,6 +412,7 @@ "reset-website": "Aby zresetować tę witrynę, wpisz {confirmation} w polu poniżej, aby potwierdzić.", "reset-website-warning": "Wszystkie statystyki tej witryny zostaną usunięte, ale kod śledzenia pozostanie nienaruszony.", "saved": "Zapisano pomyślnie.", + "select-board-entity-first": "Najpierw wybierz stronę, piksel lub link.", "select-component-preview": "Wybierz komponent do podglądu", "select-website-first": "Najpierw wybierz stronę internetową", "sever-error": "Błąd serwera", @@ -417,6 +428,7 @@ "unauthorized": "Brak autoryzacji", "user-deleted": "Użytkownik usunięty.", "viewed-page": "Obejrzana strona", + "upgrade-required": "Ta funkcja wymaga subskrypcji planu {plan}.", "visitor-log": "Odwiedzający z {country} używa {browser} na {os} {device}" } } diff --git a/public/intl/messages/pt-BR.json b/public/intl/messages/pt-BR.json index dbc38a2d3..9ee595584 100644 --- a/public/intl/messages/pt-BR.json +++ b/public/intl/messages/pt-BR.json @@ -20,10 +20,8 @@ "all-time": "Todos os períodos", "analysis": "Análise", "analytics": "Análise", - "aov": "AOV", "application": "Aplicação", "apply": "Aplicar", - "arpu": "ARPU", "attribution": "Atribuição", "attribution-description": "Veja como os usuários interagem com seu marketing e o que impulsiona conversões.", "audience": "Audiência", @@ -33,6 +31,7 @@ "behavior": "Comportamento", "block-selector": "Seletor de bloco", "boards": "Quadros", + "board-type": "Tipo de painel", "bounce-rate": "Taxa de rejeição", "breakdown": "Detalhamento", "browser": "Navegador", @@ -55,6 +54,8 @@ "confirm": "Confirmar", "confirm-password": "Confirmar senha", "contains": "Contém", + "regex-match": "Corresponde à expressão regular", + "regex-not-match": "Não corresponde à expressão regular", "content": "Conteúdo", "continue": "Continuar", "conversion": "Conversão", @@ -131,8 +132,8 @@ "funnels": "Funis", "goal": "Meta", "goals": "Metas", - "goals-description": "Acompanhe suas metas para visualizações de página e eventos.", "good": "Bom", + "goals-description": "Acompanhe suas metas para visualizações de página e eventos.", "greater-than": "Maior que", "greater-than-equals": "Maior ou igual a", "grouped": "Agrupado", @@ -140,10 +141,10 @@ "hostname": "Nome do host", "hour": "Hora", "includes": "Inclui", - "inp": "INP", "insight": "Insight", "insights": "Insights", "insights-description": "Explore seus dados em mais detalhes usando filtros", + "inp": "INP", "invalid-url": "URL inválida", "is": "É igual a", "is-false": "É falso", @@ -177,11 +178,11 @@ "manage": "Gerenciar", "manager": "Gerente", "mask-level": "Nível de máscara", + "max": "Máximo", + "max-duration": "Duração máxima", "match": "Correspondência", "match-all": "Todos", "match-any": "Qualquer", - "max": "Máximo", - "max-duration": "Duração máxima", "maximize": "Expandir", "medium": "Médio", "member": "Membro", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {registro} other {registros}}", "ok": "OK", "online": "Online", + "open": "Misto", "organic-search": "Busca orgânica", "organic-shopping": "Compras orgânicas", "organic-social": "Social orgânico", @@ -212,8 +214,8 @@ "page": "Página", "page-of": "Página {current} de {total}", "page-views": "Visualizações de página", - "pages": "Páginas", "pageTitle": "Título", + "pages": "Páginas", "paid-ads": "Anúncios pagos", "paid-search": "Busca paga", "paid-shopping": "Compras pagas", @@ -225,7 +227,6 @@ "performance": "Desempenho", "pixel": "Pixel", "pixels": "Pixels", - "play": "Reproduzir", "poor": "Ruim", "powered-by": "Desenvolvido por {name}", "preferences": "Preferências", @@ -246,16 +247,16 @@ "referrers": "Referências", "refresh": "Atualizar", "regenerate": "Gerar novamente", - "regex-match": "Corresponde à expressão regular", - "regex-not-match": "Não corresponde à expressão regular", "region": "Estado", "regions": "Estados", "remaining": "Restante", "remove": "Remover", "remove-member": "Remover membro", + "play": "Reproduzir", "replay": "Reprodução", - "replay-enabled": "Reprodução habilitada", "replay-id": "Replay ID", + "replay-code": "Código de replay da sessão", + "replay-enabled": "Reprodução habilitada", "replays": "Reproduções", "reports": "Relatórios", "required": "Obrigatório", @@ -268,21 +269,24 @@ "revenue-description": "Veja sua receita ao longo do tempo.", "role": "Função", "run-query": "Executar consulta", - "sample-rate": "Taxa de amostragem", - "sample-size": "Tamanho da amostra", "save": "Salvar", "save-cohort": "Salvar coorte", + "save-replay": "Salvar replay", "save-segment": "Salvar segmento", + "sample-rate": "Taxa de amostragem", + "sample-size": "Tamanho da amostra", "screen": "Tela", "screens": "Tamanhos de tela", "search": "Pesquisar", "segment": "Segmento", "segments": "Segmentos", "select": "Selecionar", - "select-component": "Selecionar componente", + "select-link": "Selecionar link", + "select-pixel": "Selecionar pixel", "select-date": "Selecionar data", "select-filter": "Selecionar filtro", "select-role": "Selecionar função", + "select-component": "Selecionar componente", "select-website": "Selecionar site", "session": "Sessão", "session-data": "Dados da sessão", @@ -337,9 +341,15 @@ "unique": "Únicos", "unique-events": "Eventos únicos", "unique-visitors": "Visitantes únicos", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clientes únicos", + "customers": "Clientes", + "orders": "Pedidos", + "saved": "Salvo", "unknown": "Desconhecido", "untitled": "Sem título", + "upgrade": "Atualizar", "update": "Atualizar", "url": "URL", "user": "Usuário", @@ -379,8 +389,8 @@ "confirm-reset": "Tem certeza que deseja redefinir os dados de {target}?", "delete-team-warning": "Excluir a equipe também excluirá todos os sites da equipe.", "delete-website-warning": "Todos os dados relacionados serão excluídos.", - "empty-dashboard": "Seu painel está vazio. Clique em Editar para adicionar seu primeiro componente.", "error": "Ocorreu um erro.", + "empty-dashboard": "Seu painel está vazio. Clique em Editar para adicionar seu primeiro componente.", "event-log": "{event} em {url}", "forbidden": "Proibido", "go-to-settings": "Ir para as configurações", @@ -402,6 +412,7 @@ "reset-website": "Se você tiver certeza de que deseja redefinir este site, digite {confirmation} na caixa de entrada abaixo para confirmar.", "reset-website-warning": "Todos os dados estatísticos deste site serão excluídos, mas seu código de rastreamento permanecerá o mesmo.", "saved": "Salvo com sucesso.", + "select-board-entity-first": "Selecione primeiro um site, pixel ou link.", "select-component-preview": "Selecione um componente para visualizar", "select-website-first": "Selecione um site primeiro", "sever-error": "Erro do servidor", @@ -417,6 +428,7 @@ "unauthorized": "Não autorizado", "user-deleted": "Usuário excluído.", "viewed-page": "Página visualizada", + "upgrade-required": "Este recurso requer uma assinatura do plano {plan}.", "visitor-log": "Visitante de {country} usando o navegador {browser} em um {device} com sistema operacional {os}." } } diff --git a/public/intl/messages/pt-PT.json b/public/intl/messages/pt-PT.json index 25915dacb..625b60d01 100644 --- a/public/intl/messages/pt-PT.json +++ b/public/intl/messages/pt-PT.json @@ -20,10 +20,8 @@ "all-time": "Todo o tempo", "analysis": "Análise", "analytics": "Análise", - "aov": "AOV", "application": "Aplicação", "apply": "Aplicar", - "arpu": "ARPU", "attribution": "Atribuição", "attribution-description": "Veja como os utilizadores interagem com o seu marketing e o que impulsiona conversões.", "audience": "Audiência", @@ -33,6 +31,7 @@ "behavior": "Comportamento", "block-selector": "Seletor de bloco", "boards": "Quadros", + "board-type": "Tipo de painel", "bounce-rate": "Taxa de rejeição", "breakdown": "Detalhamento", "browser": "Navegador", @@ -55,6 +54,8 @@ "confirm": "Confirmar", "confirm-password": "Confirmar senha", "contains": "Contém", + "regex-match": "Corresponde à expressão regular", + "regex-not-match": "Não corresponde à expressão regular", "content": "Conteúdo", "continue": "Continuar", "conversion": "Conversão", @@ -131,8 +132,8 @@ "funnels": "Funis", "goal": "Objetivo", "goals": "Objetivos", - "goals-description": "Acompanhe os seus objetivos para visualizações de página e eventos.", "good": "Bom", + "goals-description": "Acompanhe os seus objetivos para visualizações de página e eventos.", "greater-than": "Maior que", "greater-than-equals": "Maior ou igual a", "grouped": "Agrupado", @@ -140,10 +141,10 @@ "hostname": "Nome do host", "hour": "Hora", "includes": "Inclui", - "inp": "INP", "insight": "Insight", "insights": "Insights", "insights-description": "Aprofunde os seus dados utilizando segmentos e filtros.", + "inp": "INP", "invalid-url": "URL inválido", "is": "É", "is-false": "É falso", @@ -177,11 +178,11 @@ "manage": "Gerir", "manager": "Gestor", "mask-level": "Nível de máscara", + "max": "Máximo", + "max-duration": "Duração máxima", "match": "Correspondência", "match-all": "Todos", "match-any": "Qualquer", - "max": "Máximo", - "max-duration": "Duração máxima", "maximize": "Expandir", "medium": "Médio", "member": "Membro", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {registo} other {registos}}", "ok": "OK", "online": "Online", + "open": "Misto", "organic-search": "Pesquisa orgânica", "organic-shopping": "Compras orgânicas", "organic-social": "Social orgânico", @@ -212,8 +214,8 @@ "page": "Página", "page-of": "Página {current} de {total}", "page-views": "Visualizações da página", - "pages": "Páginas", "pageTitle": "Título da página", + "pages": "Páginas", "paid-ads": "Anúncios pagos", "paid-search": "Pesquisa paga", "paid-shopping": "Compras pagas", @@ -225,7 +227,6 @@ "performance": "Desempenho", "pixel": "Pixel", "pixels": "Píxeis", - "play": "Reproduzir", "poor": "Mau", "powered-by": "Distribuído por {name}", "preferences": "Preferências", @@ -246,16 +247,16 @@ "referrers": "Referenciadores", "refresh": "Atualizar", "regenerate": "Regenerar", - "regex-match": "Corresponde à expressão regular", - "regex-not-match": "Não corresponde à expressão regular", "region": "Região", "regions": "Regiões", "remaining": "Restante", "remove": "Remover", "remove-member": "Remover membro", + "play": "Reproduzir", "replay": "Reprodução", - "replay-enabled": "Reprodução ativada", "replay-id": "Replay ID", + "replay-code": "Código de repetição de sessão", + "replay-enabled": "Reprodução ativada", "replays": "Reproduções", "reports": "Relatórios", "required": "Obrigatório", @@ -268,21 +269,24 @@ "revenue-description": "Veja a sua receita ao longo do tempo.", "role": "Função", "run-query": "Executar consulta", - "sample-rate": "Taxa de amostragem", - "sample-size": "Tamanho da amostra", "save": "Guardar", "save-cohort": "Guardar coorte", + "save-replay": "Guardar repetição", "save-segment": "Guardar segmento", + "sample-rate": "Taxa de amostragem", + "sample-size": "Tamanho da amostra", "screen": "Ecrã", "screens": "Ecrãs", "search": "Pesquisar", "segment": "Segmento", "segments": "Segmentos", "select": "Selecionar", - "select-component": "Selecionar componente", + "select-link": "Selecionar ligação", + "select-pixel": "Selecionar pixel", "select-date": "Selecionar data", "select-filter": "Selecionar filtro", "select-role": "Selecionar função", + "select-component": "Selecionar componente", "select-website": "Selecionar website", "session": "Sessão", "session-data": "Dados da sessão", @@ -337,9 +341,15 @@ "unique": "Único", "unique-events": "Eventos únicos", "unique-visitors": "Visitantes únicos", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clientes únicos", + "customers": "Clientes", + "orders": "Encomendas", + "saved": "Guardado", "unknown": "Desconhecido", "untitled": "Sem título", + "upgrade": "Atualizar", "update": "Atualizar", "url": "URL", "user": "Utilizador", @@ -379,8 +389,8 @@ "confirm-reset": "Tem a certeza que pretende restaurar as estatísticas de {target}?", "delete-team-warning": "Eliminar uma equipa também elimina todos os websites da equipa.", "delete-website-warning": "Todos os dados associados também serão eliminados.", - "empty-dashboard": "O seu painel está vazio. Clique em Editar para adicionar o seu primeiro componente.", "error": "Ocorreu um erro.", + "empty-dashboard": "O seu painel está vazio. Clique em Editar para adicionar o seu primeiro componente.", "event-log": "{event} em {url}", "forbidden": "Proibido", "go-to-settings": "Ir para as definições", @@ -402,6 +412,7 @@ "reset-website": "Para repor este website, escreva {confirmation} na caixa abaixo para confirmar.", "reset-website-warning": "Todas as estatísticas deste site serão eliminadas, mas o seu código de rastreamento permanecerá intacto.", "saved": "Guardado com sucesso.", + "select-board-entity-first": "Selecione primeiro um website, pixel ou ligação.", "select-component-preview": "Selecione um componente para pré-visualizar", "select-website-first": "Selecione primeiro um site", "sever-error": "Erro do servidor", @@ -417,6 +428,7 @@ "unauthorized": "Não autorizado", "user-deleted": "Utilizador eliminado.", "viewed-page": "Página visualizada", + "upgrade-required": "Esta funcionalidade requer uma subscrição do plano {plan}.", "visitor-log": "Visitante de {country} a usar {browser} no {device} {os}" } } diff --git a/public/intl/messages/ro-RO.json b/public/intl/messages/ro-RO.json index bc6805a5f..b9f010d09 100644 --- a/public/intl/messages/ro-RO.json +++ b/public/intl/messages/ro-RO.json @@ -20,10 +20,8 @@ "all-time": "Pentru tot timpul", "analysis": "Analiză", "analytics": "Analiză", - "aov": "AOV", "application": "Aplicație", "apply": "Aplică", - "arpu": "ARPU", "attribution": "Atribuire", "attribution-description": "Vezi cum utilizatorii interacționează cu marketingul tău și ce determină conversiile.", "audience": "Audiență", @@ -33,6 +31,7 @@ "behavior": "Comportament", "block-selector": "Selector de bloc", "boards": "Panouri", + "board-type": "Tip de tablou", "bounce-rate": "Rata de respingere", "breakdown": "Detaliat", "browser": "Browser", @@ -55,6 +54,8 @@ "confirm": "Confirmă", "confirm-password": "Confirmare parolă", "contains": "Conține", + "regex-match": "Se potrivește cu expresia regulată", + "regex-not-match": "Nu se potrivește cu expresia regulată", "content": "Conținut", "continue": "Continuă", "conversion": "Conversie", @@ -131,8 +132,8 @@ "funnels": "Parcursuri", "goal": "Obiectiv", "goals": "Obiective", - "goals-description": "Urmărește obiectivele de vizualizări și evenimente.", "good": "Bun", + "goals-description": "Urmărește obiectivele de vizualizări și evenimente.", "greater-than": "Mai mare decât", "greater-than-equals": "Mai mare sau egal cu", "grouped": "Grupat", @@ -140,10 +141,10 @@ "hostname": "Nume gazdă", "hour": "Oră", "includes": "Include", - "inp": "INP", "insight": "Perspectivă", "insights": "Perspective", "insights-description": "Aprofundează datele utilizând segmente și filtre.", + "inp": "INP", "invalid-url": "URL invalid", "is": "Este", "is-false": "Este fals", @@ -177,11 +178,11 @@ "manage": "Administrează", "manager": "Manager", "mask-level": "Nivel mască", + "max": "Max", + "max-duration": "Durată maximă", "match": "Potrivire", "match-all": "Toate", "match-any": "Oricare", - "max": "Max", - "max-duration": "Durată maximă", "maximize": "Extinde", "medium": "Mediu", "member": "Membru", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {înregistrare} other {înregistrări}}", "ok": "OK", "online": "Online", + "open": "Mixt", "organic-search": "Căutare organică", "organic-shopping": "Cumpărături organice", "organic-social": "Social organic", @@ -212,8 +214,8 @@ "page": "Pagină", "page-of": "Pagina {current} din {total}", "page-views": "Vizualizări de pagină", - "pages": "Pagini", "pageTitle": "Titlul paginii", + "pages": "Pagini", "paid-ads": "Reclame plătite", "paid-search": "Căutare plătită", "paid-shopping": "Cumpărături plătite", @@ -225,7 +227,6 @@ "performance": "Performanță", "pixel": "Pixel", "pixels": "Pixeli", - "play": "Redă", "poor": "Slab", "powered-by": "Cu sprijinul {name}", "preferences": "Preferințe", @@ -246,16 +247,16 @@ "referrers": "Site-uri de proveniență", "refresh": "Reîmprospătare", "regenerate": "Regenerează", - "regex-match": "Se potrivește cu expresia regulată", - "regex-not-match": "Nu se potrivește cu expresia regulată", "region": "Regiune", "regions": "Regiuni", "remaining": "Rămas", "remove": "Îndepărtează", "remove-member": "Îndepărtează membru", + "play": "Redă", "replay": "Reluare", - "replay-enabled": "Reluare activată", "replay-id": "Replay ID", + "replay-code": "Cod de reluare sesiune", + "replay-enabled": "Reluare activată", "replays": "Reluări", "reports": "Rapoarte", "required": "Obligatoriu", @@ -268,21 +269,24 @@ "revenue-description": "Urmărește venitul în timp.", "role": "Rol", "run-query": "Execută interogarea", - "sample-rate": "Rată de eșantionare", - "sample-size": "Dimensiunea eșantionului", "save": "Salvează", "save-cohort": "Salvează cohorta", + "save-replay": "Salvează reluarea", "save-segment": "Salvează segmentul", + "sample-rate": "Rată de eșantionare", + "sample-size": "Dimensiunea eșantionului", "screen": "Ecran", "screens": "Ecrane", "search": "Căutare", "segment": "Segment", "segments": "Segmente", "select": "Selectează", - "select-component": "Selectați componenta", + "select-link": "Selectează link", + "select-pixel": "Selectează pixel", "select-date": "Selectează data", "select-filter": "Selectează filtru", "select-role": "Selectează rolul", + "select-component": "Selectați componenta", "select-website": "Selectează website", "session": "Sesiune", "session-data": "Date sesiune", @@ -337,9 +341,15 @@ "unique": "Unici", "unique-events": "Evenimente unice", "unique-visitors": "Vizitatori unici", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Clienți unici", + "customers": "Clienți", + "orders": "Comenzi", + "saved": "Salvat", "unknown": "Necunoscut", "untitled": "Fără titlu", + "upgrade": "Actualizează", "update": "Actualizează", "url": "URL", "user": "Utilizator", @@ -379,8 +389,8 @@ "confirm-reset": "Ești sigur că vrei să resetezi statisticile pentru {target}?", "delete-team-warning": "Ștergerea unei echipe va șterge și toate website-urile echipei.", "delete-website-warning": "Toate datele asociate vor fi șterse, de asemenea.", - "empty-dashboard": "Tabloul de bord este gol. Faceți clic pe Editare pentru a adăuga primul component.", "error": "Ceva n-a mers bine.", + "empty-dashboard": "Tabloul de bord este gol. Faceți clic pe Editare pentru a adăuga primul component.", "event-log": "{event} la {url}", "forbidden": "Interzis", "go-to-settings": "Mergi la Setări", @@ -402,6 +412,7 @@ "reset-website": "Pentru a reseta acest website, scrie {confirmation} În câmpul de mai jos pentru a confirma.", "reset-website-warning": "Toate statisticile pentru acest site web vor fi șterse, dar codul de urmărire va rămâne intact.", "saved": "Salvat cu succes.", + "select-board-entity-first": "Selectați mai întâi un site web, pixel sau link.", "select-component-preview": "Selectați o componentă pentru previzualizare", "select-website-first": "Selectați mai întâi un site web", "sever-error": "Eroare de server", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizat", "user-deleted": "Utilizator șters.", "viewed-page": "Pagină vizualizată", + "upgrade-required": "Această funcție necesită un abonament {plan}.", "visitor-log": "Vizitator din {country} folosind {browser} pe {os} {device}" } } diff --git a/public/intl/messages/sk-SK.json b/public/intl/messages/sk-SK.json index 070470190..d55ea416d 100644 --- a/public/intl/messages/sk-SK.json +++ b/public/intl/messages/sk-SK.json @@ -20,10 +20,8 @@ "all-time": "Celý čas", "analysis": "Analýza", "analytics": "Analytika", - "aov": "AOV", "application": "Aplikácia", "apply": "Použiť", - "arpu": "ARPU", "attribution": "Priradenie", "attribution-description": "Pozrite sa, ako používatelia interagujú s vaším marketingom a čo vedie ku konverziám.", "audience": "Publikum", @@ -33,6 +31,7 @@ "behavior": "Správanie", "block-selector": "Výber bloku", "boards": "Tabule", + "board-type": "Typ nástenky", "bounce-rate": "Okamžité opustenie", "breakdown": "Rozpis", "browser": "Prehliadač", @@ -55,6 +54,8 @@ "confirm": "Potvrdiť", "confirm-password": "Potvrdiť heslo", "contains": "Obsahuje", + "regex-match": "Zodpovedá regulárnemu výrazu", + "regex-not-match": "Nezodpovedá regulárnemu výrazu", "content": "Obsah", "continue": "Pokračovať", "conversion": "Konverzia", @@ -131,8 +132,8 @@ "funnels": "Lieviky", "goal": "Cieľ", "goals": "Ciele", - "goals-description": "Sledujte svoje ciele pre zobrazenia stránok a udalosti.", "good": "Dobré", + "goals-description": "Sledujte svoje ciele pre zobrazenia stránok a udalosti.", "greater-than": "Väčšie ako", "greater-than-equals": "Väčšie alebo rovné", "grouped": "Zoskupené", @@ -140,10 +141,10 @@ "hostname": "Názov hostiteľa", "hour": "Hodina", "includes": "Zahŕňa", - "inp": "INP", "insight": "Prehľad", "insights": "Prehľady", "insights-description": "Ponorte sa hlbšie do vašich dát pomocou segmentov a filtrov.", + "inp": "INP", "invalid-url": "Neplatná URL", "is": "Je", "is-false": "Je nepravda", @@ -177,11 +178,11 @@ "manage": "Spravovať", "manager": "Manažér", "mask-level": "Úroveň masky", + "max": "Maximum", + "max-duration": "Maximálne trvanie", "match": "Zhoda", "match-all": "Všetky", "match-any": "Akýkoľvek", - "max": "Maximum", - "max-duration": "Maximálne trvanie", "maximize": "Rozbaliť", "medium": "Stredný", "member": "Člen", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {záznam} few {záznamy} other {záznamov}}", "ok": "OK", "online": "Online", + "open": "Zmiešaný", "organic-search": "Organické vyhľadávanie", "organic-shopping": "Organické nakupovanie", "organic-social": "Organické sociálne siete", @@ -212,8 +214,8 @@ "page": "Stránka", "page-of": "Strana {current} z {total}", "page-views": "Zobrazenie stánok", - "pages": "Stránky", "pageTitle": "Názov stránky", + "pages": "Stránky", "paid-ads": "Platené reklamy", "paid-search": "Platené vyhľadávanie", "paid-shopping": "Platené nakupovanie", @@ -225,7 +227,6 @@ "performance": "Výkon", "pixel": "Pixel", "pixels": "Pixely", - "play": "Prehrať", "poor": "Zlé", "powered-by": "Poskytuje {name}", "preferences": "Predvoľby", @@ -246,16 +247,16 @@ "referrers": "Odkazy", "refresh": "Obnoviť", "regenerate": "Regenerovať", - "regex-match": "Zodpovedá regulárnemu výrazu", - "regex-not-match": "Nezodpovedá regulárnemu výrazu", "region": "Región", "regions": "Regióny", "remaining": "Zostáva", "remove": "Odstrániť", "remove-member": "Odstrániť člena", + "play": "Prehrať", "replay": "Prehrávanie", - "replay-enabled": "Prehrávanie povolené", "replay-id": "Replay ID", + "replay-code": "Kód prehrania relácie", + "replay-enabled": "Prehrávanie povolené", "replays": "Prehrávanie", "reports": "Správy", "required": "Povinné", @@ -268,21 +269,24 @@ "revenue-description": "Pozrite si svoj príjem v priebehu času.", "role": "Rola", "run-query": "Spustiť dotaz", - "sample-rate": "Frekvencia vzorkovania", - "sample-size": "Veľkosť vzorky", "save": "Uložiť", "save-cohort": "Uložiť kohortu", + "save-replay": "Uložiť prehranie", "save-segment": "Uložiť segment", + "sample-rate": "Frekvencia vzorkovania", + "sample-size": "Veľkosť vzorky", "screen": "Obrazovka", "screens": "Obrazovky", "search": "Hľadať", "segment": "Segment", "segments": "Segmenty", "select": "Vybrať", - "select-component": "Vyberte komponent", + "select-link": "Vybrať odkaz", + "select-pixel": "Vybrať pixel", "select-date": "Vybrať dátum", "select-filter": "Vybrať filter", "select-role": "Vybrať rolu", + "select-component": "Vyberte komponent", "select-website": "Vybrať web", "session": "Sedenie", "session-data": "Dáta sedenia", @@ -337,9 +341,15 @@ "unique": "Unikátny", "unique-events": "Unikátne udalosti", "unique-visitors": "Jedinečné návštevy", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unikátni zákazníci", + "customers": "Zákazníci", + "orders": "Objednávky", + "saved": "Uložené", "unknown": "Neznámý", "untitled": "Bez názvu", + "upgrade": "Inovovať", "update": "Aktualizovať", "url": "URL", "user": "Používateľ", @@ -379,8 +389,8 @@ "confirm-reset": "Are your sure you want to reset {target}'s statistics?", "delete-team-warning": "Vymazanie tímu vymaže aj všetky weby tímu.", "delete-website-warning": "Všetky príbuzné data budu tiež zmazané.", - "empty-dashboard": "Váš dashboard je prázdny. Kliknite na Upraviť a pridajte prvý komponent.", "error": "Niečo sa pokazilo.", + "empty-dashboard": "Váš dashboard je prázdny. Kliknite na Upraviť a pridajte prvý komponent.", "event-log": "{event} na {url}", "forbidden": "Zakázané", "go-to-settings": "Ísť do nastavení", @@ -402,6 +412,7 @@ "reset-website": "Na resetovanie tohto webu zadajte {confirmation} do poľa nižšie.", "reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.", "saved": "Úspešne uložené.", + "select-board-entity-first": "Najprv vyberte webovú stránku, pixel alebo odkaz.", "select-component-preview": "Vyberte komponent na náhľad", "select-website-first": "Najprv vyberte webovú stránku", "sever-error": "Chyba servera", @@ -417,6 +428,7 @@ "unauthorized": "Neautorizované", "user-deleted": "Používateľ vymazaný.", "viewed-page": "Zobrazená stránka", + "upgrade-required": "Táto funkcia vyžaduje predplatné plánu {plan}.", "visitor-log": "Návštevník z {country} s prehliadačom {browser} na {os} {device}" } } diff --git a/public/intl/messages/sl-SI.json b/public/intl/messages/sl-SI.json index 58a218858..7e4573297 100644 --- a/public/intl/messages/sl-SI.json +++ b/public/intl/messages/sl-SI.json @@ -20,10 +20,8 @@ "all-time": "Ves čas", "analysis": "Analiza", "analytics": "Analitika", - "aov": "AOV", "application": "Aplikacija", "apply": "Uporabi", - "arpu": "ARPU", "attribution": "Pripis", "attribution-description": "Oglejte si, kako uporabniki sodelujejo z vašim marketingom in kaj spodbuja konverzije.", "audience": "Občinstvo", @@ -33,6 +31,7 @@ "behavior": "Obnašanje", "block-selector": "Izbirnik blokov", "boards": "Table", + "board-type": "Vrsta plošče", "bounce-rate": "Odbojna stopnja", "breakdown": "Razčlenitev", "browser": "Brskalnik", @@ -55,6 +54,8 @@ "confirm": "Potrdi", "confirm-password": "Potrdi geslo", "contains": "Vsebuje", + "regex-match": "Ustreza regularnemu izrazu", + "regex-not-match": "Ne ustreza regularnemu izrazu", "content": "Vsebina", "continue": "Nadaljuj", "conversion": "Konverzija", @@ -131,21 +132,19 @@ "funnels": "Prodajni lijaki", "goal": "Cilj", "goals": "Cilji", - "goals-description": "Spremljajte svoje cilje za oglede strani in dogodke.", "good": "Dobro", + "goals-description": "Spremljajte svoje cilje za oglede strani in dogodke.", "greater-than": "Večje od", "greater-than-equals": "Večje ali enako kot", "grouped": "Združeno", "growth": "Rast", - "host": "Gostitelj", "hostname": "Ime gostitelja", - "hosts": "Gostitelji", "hour": "Ura", "includes": "Vključuje", - "inp": "INP", "insight": "Vpogled", "insights": "Vpogled", "insights-description": "Poglobite se v podatke z uporabo segmentov in filtrov.", + "inp": "INP", "invalid-url": "Neveljaven URL", "is": "Je", "is-false": "Je napačno", @@ -179,11 +178,11 @@ "manage": "Upravljaj", "manager": "Upravitelj", "mask-level": "Raven maske", + "max": "Največ", + "max-duration": "Največje trajanje", "match": "Ujemanje", "match-all": "Vse", "match-any": "Katero koli", - "max": "Največ", - "max-duration": "Največje trajanje", "maximize": "Povečaj", "medium": "Medij", "member": "Član", @@ -203,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {zapis} two {zapisa} few {zapisi} other {zapisov}}", "ok": "V redu", "online": "Na spletu", + "open": "Mešano", "organic-search": "Organsko iskanje", "organic-shopping": "Organski nakupi", "organic-social": "Organska družbena omrežja", @@ -214,8 +214,8 @@ "page": "Stran", "page-of": "Stran {current} od {total}", "page-views": "Obiski strani", - "pages": "Strani", "pageTitle": "Naslov strani", + "pages": "Strani", "paid-ads": "Plačani oglasi", "paid-search": "Plačano iskanje", "paid-shopping": "Plačani nakupi", @@ -227,7 +227,6 @@ "performance": "Zmogljivost", "pixel": "Piksel", "pixels": "Piksli", - "play": "Predvajaj", "poor": "Slabo", "powered-by": "Poganja {name}", "preferences": "Nastavitve", @@ -248,16 +247,16 @@ "referrers": "Viri", "refresh": "Osveži", "regenerate": "Ponovno generiraj", - "regex-match": "Ustreza regularnemu izrazu", - "regex-not-match": "Ne ustreza regularnemu izrazu", "region": "Regija", "regions": "Regije", "remaining": "Preostalo", "remove": "Odstrani", "remove-member": "Odstrani člana", + "play": "Predvajaj", "replay": "Predvajanje", - "replay-enabled": "Predvajanje omogočeno", "replay-id": "Replay ID", + "replay-code": "Koda ponovitve seje", + "replay-enabled": "Predvajanje omogočeno", "replays": "Predvajanja", "reports": "Poročila", "required": "Zahtevano", @@ -268,24 +267,26 @@ "retention-description": "Merite uporabnikovo zadržanost s sledenjem, kako pogosto se vračajo.", "revenue": "Prihodki", "revenue-description": "Preglejte svoje prihodke skozi čas.", - "revenue-property": "Lastnost prihodkov", "role": "Vloga", "run-query": "Izvedi poizvedbo", - "sample-rate": "Hitrost vzorčenja", - "sample-size": "Velikost vzorca", "save": "Shrani", "save-cohort": "Shrani kohorto", + "save-replay": "Shrani ponovitev", "save-segment": "Shrani segment", + "sample-rate": "Hitrost vzorčenja", + "sample-size": "Velikost vzorca", "screen": "Zaslon", "screens": "Zasloni", "search": "Išči", "segment": "Segment", "segments": "Segmenti", "select": "Izberi", - "select-component": "Izberite komponento", + "select-link": "Izberi povezavo", + "select-pixel": "Izberi piksel", "select-date": "Izberi datum", "select-filter": "Izberi filter", "select-role": "Izberi vlogo", + "select-component": "Izberite komponento", "select-website": "Izberi spletno mesto", "session": "Seja", "session-data": "Podatki seje", @@ -340,9 +341,15 @@ "unique": "Unikatni", "unique-events": "Edinstveni dogodki", "unique-visitors": "Unikatni obiskovalci", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Edinstvene stranke", + "customers": "Stranke", + "orders": "Naročila", + "saved": "Shranjeno", "unknown": "Neznano", "untitled": "Brez naslova", + "upgrade": "Nadgradi", "update": "Posodobi", "url": "URL", "user": "Uporabnik", @@ -369,7 +376,10 @@ "website-id": "ID spletnega mesta", "websites": "Spletna mesta", "window": "Okno", - "yesterday": "Včeraj" + "yesterday": "Včeraj", + "host": "Gostitelj", + "hosts": "Gostitelji", + "revenue-property": "Lastnost prihodkov" }, "message": { "action-confirmation": "Za potrditev v spodnje polje vnesite {confirmation}.", @@ -382,8 +392,8 @@ "confirm-reset": "Ste prepričani, da želite ponastaviti statistiko {target}?", "delete-team-warning": "Brisanje ekipe bo izbrisalo tudi vsa spletna mesta ekipe.", "delete-website-warning": "Izbrisani bodo tudi vsi pripadajoči podatki.", - "empty-dashboard": "Vaša nadzorna plošča je prazna. Kliknite Uredi, da dodate svojo prvo komponento.", "error": "Nekaj je šlo narobe.", + "empty-dashboard": "Vaša nadzorna plošča je prazna. Kliknite Uredi, da dodate svojo prvo komponento.", "event-log": "{event} na {url}", "forbidden": "Prepovedano", "go-to-settings": "Pojdi v nastavitve", @@ -405,6 +415,7 @@ "reset-website": "Za ponastavitev izbrisa tega spletnega mesta vnesite {confirmation} v spodnje polje.", "reset-website-warning": "Vse statistike za to spletno mesto bodo izbrisane, koda za sledenje pa bo ostala nespremenjena.", "saved": "Uspešno shranjeno.", + "select-board-entity-first": "Najprej izberite spletno mesto, piksel ali povezavo.", "select-component-preview": "Izberite komponento za predogled", "select-website-first": "Najprej izberite spletno mesto", "sever-error": "Napaka strežnika", @@ -420,6 +431,7 @@ "unauthorized": "Nepooblaščen dostop", "user-deleted": "Uporabnik je izbrisan.", "viewed-page": "Ogledana stran", + "upgrade-required": "Ta funkcija zahteva naročnino na paket {plan}.", "visitor-log": "Obiskovalec iz {country} uporablja {browser} na {os} {device}", "visitors-dropped-off": "Osip obiskovalcev" } diff --git a/public/intl/messages/sv-SE.json b/public/intl/messages/sv-SE.json index e54be158c..cc175b334 100644 --- a/public/intl/messages/sv-SE.json +++ b/public/intl/messages/sv-SE.json @@ -20,10 +20,8 @@ "all-time": "Sedan början", "analysis": "Analys", "analytics": "Webbplats Analys", - "aov": "AOV", "application": "Applikation", "apply": "Tillämpa", - "arpu": "ARPU", "attribution": "Attribuering", "attribution-description": "Se hur användare interagerar med din marknadsföring och vad som driver konverteringar.", "audience": "Publik", @@ -33,6 +31,7 @@ "behavior": "Beteende", "block-selector": "Blockväljare", "boards": "Anslagstavlor", + "board-type": "Typ av tavla", "bounce-rate": "Avvisningsfrekvens", "breakdown": "Analys", "browser": "Webbläsare", @@ -55,6 +54,8 @@ "confirm": "Bekräfta", "confirm-password": "Bekräfta lösenord", "contains": "Innehåller", + "regex-match": "Matchar reguljärt uttryck", + "regex-not-match": "Matchar inte reguljärt uttryck", "content": "Innehåll", "continue": "Fortsätt", "conversion": "Konvertering", @@ -131,8 +132,8 @@ "funnels": "Trattar", "goal": "Mål", "goals": "Mål", - "goals-description": "Följ dina mål för sidvisningar och händelser.", "good": "Bra", + "goals-description": "Följ dina mål för sidvisningar och händelser.", "greater-than": "Större än", "greater-than-equals": "Större än eller lika med", "grouped": "Grupperad", @@ -140,10 +141,10 @@ "hostname": "Värdnamn", "hour": "Timme", "includes": "Inkluderar", - "inp": "INP", "insight": "Insikt", "insights": "Insikter", "insights-description": "Dyk djupare in i din data genom att använda olika segment och filter.", + "inp": "INP", "invalid-url": "Ogiltig URL", "is": "Är", "is-false": "Är falskt", @@ -177,11 +178,11 @@ "manage": "Hantera", "manager": "Ansvarig", "mask-level": "Masknivå", + "max": "Max", + "max-duration": "Maximal varaktighet", "match": "Matchning", "match-all": "Alla", "match-any": "Vilken som helst", - "max": "Max", - "max-duration": "Maximal varaktighet", "maximize": "Expandera", "medium": "Medium", "member": "Medlem", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {post} other {poster}}", "ok": "OK", "online": "Online", + "open": "Blandad", "organic-search": "Organisk sökning", "organic-shopping": "Organisk shopping", "organic-social": "Organisk social", @@ -212,8 +214,8 @@ "page": "Sida", "page-of": "Sida {current} av {total}", "page-views": "Sidvisningar", - "pages": "Sidor", "pageTitle": "Sidtitel", + "pages": "Sidor", "paid-ads": "Betalda annonser", "paid-search": "Betald sökning", "paid-shopping": "Betald shopping", @@ -225,7 +227,6 @@ "performance": "Prestanda", "pixel": "Pixel", "pixels": "Pixlar", - "play": "Spela upp", "poor": "Dålig", "powered-by": "Drivs av {name}", "preferences": "Inställningar", @@ -246,16 +247,16 @@ "referrers": "Hänvisare", "refresh": "Uppdatera", "regenerate": "Förnya", - "regex-match": "Matchar reguljärt uttryck", - "regex-not-match": "Matchar inte reguljärt uttryck", "region": "Region", "regions": "Regioner", "remaining": "Återstår", "remove": "Ta bort", "remove-member": "Ta bort medlem", + "play": "Spela upp", "replay": "Uppspelning", - "replay-enabled": "Uppspelning aktiverad", "replay-id": "Replay ID", + "replay-code": "Kod för sessionsuppspelning", + "replay-enabled": "Uppspelning aktiverad", "replays": "Uppspelningar", "reports": "Rapporter", "required": "Krävs", @@ -268,21 +269,24 @@ "revenue-description": "Se dina intäkter över tid.", "role": "Roll", "run-query": "Kör sökning", - "sample-rate": "Samplingshastighet", - "sample-size": "Urvalsstorlek", "save": "Spara", "save-cohort": "Spara kohort", + "save-replay": "Spara uppspelning", "save-segment": "Spara segment", + "sample-rate": "Samplingshastighet", + "sample-size": "Urvalsstorlek", "screen": "Skärm", "screens": "Upplösning", "search": "Sök", "segment": "Segment", "segments": "Segment", "select": "Välj", - "select-component": "Välj komponent", + "select-link": "Välj länk", + "select-pixel": "Välj pixel", "select-date": "Välj datum", "select-filter": "Välj filter", "select-role": "Välj roll", + "select-component": "Välj komponent", "select-website": "Välj webbplats", "session": "Session", "session-data": "Sessionsdata", @@ -337,9 +341,15 @@ "unique": "Unikt", "unique-events": "Unika händelser", "unique-visitors": "Unika besökare", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Unika kunder", + "customers": "Kunder", + "orders": "Beställningar", + "saved": "Sparad", "unknown": "Okänt", "untitled": "Namnlös", + "upgrade": "Uppgradera", "update": "Uppdatera", "url": "URL", "user": "Användare", @@ -379,8 +389,8 @@ "confirm-reset": "Är du säker på att du vill återställa statistiken för {target}?", "delete-team-warning": "Att radera ett team raderar även alla teamets webbplatser.", "delete-website-warning": "All tillhörande data kommer också att raderas.", - "empty-dashboard": "Din instrumentpanel är tom. Klicka på Redigera för att lägga till din första komponent.", "error": "Något gick fel.", + "empty-dashboard": "Din instrumentpanel är tom. Klicka på Redigera för att lägga till din första komponent.", "event-log": "{event}{url}", "forbidden": "Förbjudet", "go-to-settings": "Gå till inställningar", @@ -402,6 +412,7 @@ "reset-website": "För att återställa webbplatsen, skriv {confirmation} i rutan nedan.", "reset-website-warning": "All statistik för webbplatsen tas bort, men spårningskoden förblir oförändrad.", "saved": "Sparat!", + "select-board-entity-first": "Välj först en webbplats, pixel eller länk.", "select-component-preview": "Välj en komponent för att förhandsgranska", "select-website-first": "Välj en webbplats först", "sever-error": "Serverfel", @@ -417,6 +428,7 @@ "unauthorized": "Inte auktoriserad", "user-deleted": "Användaren har raderats.", "viewed-page": "Visad sida", + "upgrade-required": "Den här funktionen kräver en {plan}-prenumeration.", "visitor-log": "Besökare från {country} med {browser}{os} {device}" } } diff --git a/public/intl/messages/tr-TR.json b/public/intl/messages/tr-TR.json index 2aa104940..7c915c393 100644 --- a/public/intl/messages/tr-TR.json +++ b/public/intl/messages/tr-TR.json @@ -20,10 +20,8 @@ "all-time": "Tüm zamanlar", "analysis": "Analiz", "analytics": "Analitik", - "aov": "AOV", "application": "Uygulama", "apply": "Uygula", - "arpu": "ARPU", "attribution": "Atıf", "attribution-description": "Kullanıcıların pazarlamanızla nasıl etkileşime girdiğini ve dönüşümleri neyin tetiklediğini görün.", "audience": "Kitle", @@ -33,6 +31,7 @@ "behavior": "Davranış", "block-selector": "Blok seçici", "boards": "Panolar", + "board-type": "Pano türü", "bounce-rate": "Tek sayfa ziyaret oranı", "breakdown": "Dağılım", "browser": "Tarayıcı", @@ -55,6 +54,8 @@ "confirm": "Onayla", "confirm-password": "Parolayı onayla", "contains": "İçeriği", + "regex-match": "Düzenli ifadeyle eşleşir", + "regex-not-match": "Düzenli ifadeyle eşleşmez", "content": "İçerik", "continue": "Devam et", "conversion": "Dönüşüm", @@ -131,8 +132,8 @@ "funnels": "Huniler", "goal": "Hedef", "goals": "Hedefler", - "goals-description": "Sayfa görüntüleme ve olaylar için hedeflerinizi takip edin.", "good": "İyi", + "goals-description": "Sayfa görüntüleme ve olaylar için hedeflerinizi takip edin.", "greater-than": "Büyüktür", "greater-than-equals": "Büyük veya eşittir", "grouped": "Gruplandırılmış", @@ -140,10 +141,10 @@ "hostname": "Sunucu adı", "hour": "Saat", "includes": "İçerir", - "inp": "INP", "insight": "İçgörü", "insights": "İçgörüler", "insights-description": "Segmentleri ve filtreleri kullanarak verilerinizi derinlemesine inceleyin.", + "inp": "INP", "invalid-url": "Geçersiz URL", "is": "Eşittir", "is-false": "Yanlış", @@ -177,11 +178,11 @@ "manage": "Yönet", "manager": "Yönetici", "mask-level": "Maske seviyesi", + "max": "Maks", + "max-duration": "Maksimum süre", "match": "Eşleşme", "match-all": "Tümü", "match-any": "Herhangi", - "max": "Maks", - "max-duration": "Maksimum süre", "maximize": "Genişlet", "medium": "Orta", "member": "Üye", @@ -201,6 +202,7 @@ "number-of-records": "{x} {x, plural, one {kayıt} other {kayıt}}", "ok": "TAMAM", "online": "Çevrimiçi", + "open": "Karışık", "organic-search": "Organik arama", "organic-shopping": "Organik alışveriş", "organic-social": "Organik sosyal", @@ -212,8 +214,8 @@ "page": "Sayfa", "page-of": "{total} sayfada {current} ", "page-views": "Sayfa görünümü", - "pages": "Sayfalar", "pageTitle": "Sayfa başlığı", + "pages": "Sayfalar", "paid-ads": "Ücretli reklamlar", "paid-search": "Ücretli arama", "paid-shopping": "Ücretli alışveriş", @@ -225,7 +227,6 @@ "performance": "Performans", "pixel": "Piksel", "pixels": "Pikseller", - "play": "Oynat", "poor": "Kötü", "powered-by": "Sağlayıcı: {name}", "preferences": "Tercihler", @@ -246,16 +247,16 @@ "referrers": "Yönlendirenler", "refresh": "Yenile", "regenerate": "Yeniden Oluştur", - "regex-match": "Düzenli ifadeyle eşleşir", - "regex-not-match": "Düzenli ifadeyle eşleşmez", "region": "Bölge", "regions": "Bölgeler", "remaining": "Kalan", "remove": "Kaldır", "remove-member": "Üyeyi kaldır", + "play": "Oynat", "replay": "Tekrar oynatma", - "replay-enabled": "Tekrar oynatma etkin", "replay-id": "Replay ID", + "replay-code": "Oturum tekrar oynatma kodu", + "replay-enabled": "Tekrar oynatma etkin", "replays": "Tekrar oynatmalar", "reports": "Raporlar", "required": "Zorunlu alan", @@ -268,21 +269,24 @@ "revenue-description": "Gelirinizi zaman içinde inceleyin.", "role": "Rol", "run-query": "Sorgu çalıştır", - "sample-rate": "Örnekleme hızı", - "sample-size": "Örneklem boyutu", "save": "Kaydet", "save-cohort": "Kohortu kaydet", + "save-replay": "Tekrarı kaydet", "save-segment": "Segmenti kaydet", + "sample-rate": "Örnekleme hızı", + "sample-size": "Örneklem boyutu", "screen": "Ekran", "screens": "Ekranlar", "search": "Ara", "segment": "Segment", "segments": "Segmentler", "select": "Seç", - "select-component": "Bileşen seçin", + "select-link": "Bağlantı seç", + "select-pixel": "Piksel seç", "select-date": "Tarih seç", "select-filter": "Filtre seç", "select-role": "Rol seç", + "select-component": "Bileşen seçin", "select-website": "Web sitesi seç", "session": "Oturum", "session-data": "Oturum verisi", @@ -337,9 +341,15 @@ "unique": "Benzersiz", "unique-events": "Benzersiz etkinlikler", "unique-visitors": "Tekil kullanıcı", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Benzersiz müşteriler", + "customers": "Müşteriler", + "orders": "Siparişler", + "saved": "Kaydedildi", "unknown": "Bilinmeyen", "untitled": "İsimsiz", + "upgrade": "Yükselt", "update": "Güncelle", "url": "URL", "user": "Kullanıcı", @@ -379,8 +389,8 @@ "confirm-reset": "{target} istatistiklerini sıfırlamak istediğinizden emin misiniz?", "delete-team-warning": "Bir takımı silmek tüm takım web sitelerini de silecektir.", "delete-website-warning": "İlişkili tüm veriler de silinecektir.", - "empty-dashboard": "Gösterge paneliniz boş. İlk bileşeninizi eklemek için Düzenle'ye tıklayın.", "error": "Bir şeyler ters gitti!", + "empty-dashboard": "Gösterge paneliniz boş. İlk bileşeninizi eklemek için Düzenle'ye tıklayın.", "event-log": "{event} sayfasında {url}", "forbidden": "Yasaklandı", "go-to-settings": "Ayarlara git", @@ -402,6 +412,7 @@ "reset-website": "Bu websitesini sıfılamak için aşağıdaki kutuya {confirmation} yazın.", "reset-website-warning": "Bu web sitesi için tüm istatistikler silinecek, ancak izleme kodunuz bozulmadan kalacaktır.", "saved": "Başarıyla kaydedildi.", + "select-board-entity-first": "Önce bir web sitesi, piksel veya bağlantı seçin.", "select-component-preview": "Önizleme için bir bileşen seçin", "select-website-first": "Önce bir web sitesi seçin", "sever-error": "Sunucu hatası", @@ -417,6 +428,7 @@ "unauthorized": "Yetkisiz", "user-deleted": "Kullanıcı silindi.", "viewed-page": "Görüntülenen sayfa", + "upgrade-required": "Bu özellik {plan} plan aboneliği gerektirir.", "visitor-log": "Yeni ziyaretçi: {country}, {os}, {device}, {browser}" } } diff --git a/public/intl/messages/uz-UZ.json b/public/intl/messages/uz-UZ.json index 2a1d7479a..7d61b3301 100644 --- a/public/intl/messages/uz-UZ.json +++ b/public/intl/messages/uz-UZ.json @@ -20,10 +20,8 @@ "all-time": "Barcha vaqtlar", "analysis": "Tahlil", "analytics": "Tahlil", - "aov": "AOV", "application": "Ilova", "apply": "Qoʻllash", - "arpu": "ARPU", "attribution": "Atribusiya", "attribution-description": "Foydalanuvchilar marketingingiz bilan qanday muloqot qilishlarini va konversiyalarni nimalar ragʻbatlantirganini koʻring.", "audience": "Auditoriya", @@ -33,6 +31,7 @@ "behavior": "Xulq-atvor", "block-selector": "Blok tanlash", "boards": "Taxtalar", + "board-type": "Taxta turi", "bounce-rate": "Chiqib ketish darajasi", "breakdown": "Tahlil", "browser": "Brauzer", @@ -55,6 +54,8 @@ "confirm": "Tasdiqlash", "confirm-password": "Parolni tasdiqlash", "contains": "Oʻz ichiga oladi", + "regex-match": "Muntazam ifodaga mos keladi", + "regex-not-match": "Muntazam ifodaga mos kelmaydi", "content": "Kontent", "continue": "Davom etish", "conversion": "Konversiya", @@ -131,21 +132,19 @@ "funnels": "Voronkalar", "goal": "Maqsad", "goals": "Maqsadlar", - "goals-description": "Sahifa koʻrishlari va hodisalar uchun maqsadlaringizni kuzatib boring.", "good": "Yaxshi", + "goals-description": "Sahifa koʻrishlari va hodisalar uchun maqsadlaringizni kuzatib boring.", "greater-than": "Kattaroq", "greater-than-equals": "Kattaroq yoki teng", "grouped": "Guruhlangan", "growth": "O'sish", - "host": "Xost", "hostname": "Xost nomi", - "hosts": "Xostlar", "hour": "Soat", "includes": "Oʻz ichiga oladi", - "inp": "INP", "insight": "Tushuncha", "insights": "Tushunchalar", "insights-description": "Segmentlar va filtrlardan foydalanib ma'lumotlaringizga chuqurroq kiring.", + "inp": "INP", "invalid-url": "Noto'g'ri URL", "is": "Teng", "is-false": "Yolgʻon", @@ -179,11 +178,11 @@ "manage": "Boshqarish", "manager": "Menejer", "mask-level": "Niqob darajasi", + "max": "Maksimal", + "max-duration": "Maksimal davomiylik", "match": "Moslik", "match-all": "Barchasi", "match-any": "Istalgan", - "max": "Maksimal", - "max-duration": "Maksimal davomiylik", "maximize": "Kattalashtirish", "medium": "Vosita", "member": "A'zo", @@ -203,6 +202,7 @@ "number-of-records": "{x} yozuv", "ok": "OK", "online": "Onlayn", + "open": "Aralash", "organic-search": "Organik qidiruv", "organic-shopping": "Organik xarid", "organic-social": "Organik ijtimoiy", @@ -214,8 +214,8 @@ "page": "Sahifa", "page-of": "Sahifa {current} dan {total}", "page-views": "Sahifa koʻrishlari", - "pages": "Sahifalar", "pageTitle": "Sahifa sarlavhasi", + "pages": "Sahifalar", "paid-ads": "Pullik reklamalar", "paid-search": "Pullik qidiruv", "paid-shopping": "Pullik xarid", @@ -227,7 +227,6 @@ "performance": "Ishlash", "pixel": "Piksel", "pixels": "Piksellar", - "play": "Ijro etish", "poor": "Yomon", "powered-by": "{name} tomonidan quvvatlanadi", "preferences": "Sozlamalar", @@ -248,16 +247,16 @@ "referrers": "Tavsiya etuvchilar", "refresh": "Yangilash", "regenerate": "Qayta yaratish", - "regex-match": "Muntazam ifodaga mos keladi", - "regex-not-match": "Muntazam ifodaga mos kelmaydi", "region": "Viloyat/Mintaqa", "regions": "Viloyatlar/Mintaqalar", "remaining": "Qolgan", "remove": "Olib tashlash", "remove-member": "A'zoni olib tashlash", + "play": "Ijro etish", "replay": "Qayta ijro", - "replay-enabled": "Qayta ijro yoqilgan", "replay-id": "Replay ID", + "replay-code": "Sessiya takrorlash kodi", + "replay-enabled": "Qayta ijro yoqilgan", "replays": "Qayta ijrolar", "reports": "Hisobotlar", "required": "Majburiy", @@ -268,24 +267,26 @@ "retention-description": "Foydalanuvchilarning qaytish chastotasini kuzatib, veb-saytingizning jozibadorligini oʻlchang.", "revenue": "Daromad", "revenue-description": "Vaqt oʻtishi bilan daromadingizni tekshiring.", - "revenue-property": "Daromad xususiyati", "role": "Rol", "run-query": "Soʻrovni ishga tushirish", - "sample-rate": "Namuna olish tezligi", - "sample-size": "Namuna hajmi", "save": "Saqlash", "save-cohort": "Kogortani saqlash", + "save-replay": "Takrorlashni saqlash", "save-segment": "Segmentni saqlash", + "sample-rate": "Namuna olish tezligi", + "sample-size": "Namuna hajmi", "screen": "Ekran", "screens": "Ekranlar", "search": "Qidiruv", "segment": "Segment", "segments": "Segmentlar", "select": "Tanlash", - "select-component": "Komponent tanlash", + "select-link": "Havolani tanlash", + "select-pixel": "Pikselni tanlash", "select-date": "Sanani tanlash", "select-filter": "Filtrni tanlash", "select-role": "Rolni tanlash", + "select-component": "Komponent tanlash", "select-website": "Veb-saytni tanlash", "session": "Sessiya", "session-data": "Sessiya maʼlumotlari", @@ -340,14 +341,18 @@ "unique": "Noyob", "unique-events": "Noyob hodisalar", "unique-visitors": "Noyob tashrif buyuruvchilar", + "aov": "AOV", + "arpu": "ARPU", "uniqueCustomers": "Noyob mijozlar", + "customers": "Mijozlar", + "orders": "Buyurtmalar", + "saved": "Saqlandi", "unknown": "Noma'lum", "untitled": "Sarlavhasiz", + "upgrade": "Yangilash", "update": "Yangilash", "url": "URL", - "urls": "URL'lar", "user": "Foydalanuvchi", - "user-property": "Foydalanuvchi xususiyati", "username": "Foydalanuvchi nomi", "users": "Foydalanuvchilar", "utm": "UTM", @@ -371,7 +376,12 @@ "website-id": "Veb-sayt ID'si", "websites": "Veb-saytlar", "window": "Oyna", - "yesterday": "Kecha" + "yesterday": "Kecha", + "host": "Xost", + "hosts": "Xostlar", + "revenue-property": "Daromad xususiyati", + "urls": "URL'lar", + "user-property": "Foydalanuvchi xususiyati" }, "message": { "action-confirmation": "Tasdiqlash uchun pastdagi qutiga **{confirmation}** yozing.", @@ -384,8 +394,8 @@ "confirm-reset": "**{target}** ni qayta tiklamoqchi ekanligingizga ishonchingiz komilmi?", "delete-team-warning": "Jamoani oʻchirish, shuningdek, barcha jamoa veb-saytlarini ham oʻchiradi.", "delete-website-warning": "Barcha veb-sayt ma'lumotlari oʻchiriladi.", - "empty-dashboard": "Sizning boshqaruv panelingiz bo'sh. Birinchi komponentni qo'shish uchun Tahrirlash tugmasini bosing.", "error": "Nimadir xato ketdi.", + "empty-dashboard": "Sizning boshqaruv panelingiz bo'sh. Birinchi komponentni qo'shish uchun Tahrirlash tugmasini bosing.", "event-log": "**{url}** da **{event}** hodisasi", "forbidden": "Taqiqlangan", "go-to-settings": "Sozlamalarga oʻtish", @@ -407,6 +417,7 @@ "reset-website": "Bu veb-saytni qayta tiklash uchun tasdiqlash uchun pastdagi qutiga **{confirmation}** yozing.", "reset-website-warning": "Bu veb-sayt uchun barcha statistik ma'lumotlar oʻchiriladi, lekin sozlamalaringiz saqlanib qoladi.", "saved": "Saqlandi.", + "select-board-entity-first": "Avval veb-sayt, piksel yoki havolani tanlang.", "select-component-preview": "Ko'rib chiqish uchun komponent tanlang", "select-website-first": "Avval veb-sayt tanlang", "sever-error": "Server xatosi", @@ -422,6 +433,7 @@ "unauthorized": "Ruxsatsiz", "user-deleted": "Foydalanuvchi oʻchirildi.", "viewed-page": "Sahifa koʻrildi", + "upgrade-required": "Bu xususiyat {plan} tarif obunasini talab qiladi.", "visitor-log": "{os} {device} da {browser} dan foydalanayotgan {country} dan tashrif buyuruvchi", "visitors-dropped-off": "Tashrif buyuruvchilar tashlab ketishdi" } diff --git a/src/app/(main)/boards/BoardsTable.tsx b/src/app/(main)/boards/BoardsTable.tsx index 104a58fc8..b21cbee00 100644 --- a/src/app/(main)/boards/BoardsTable.tsx +++ b/src/app/(main)/boards/BoardsTable.tsx @@ -18,6 +18,9 @@ export function BoardsTable(props: DataTableProps) { }} + + {({ type }: any) => type ? type.charAt(0).toUpperCase() + type.slice(1) : ''} + {(row: any) => } diff --git a/src/app/(main)/boards/[boardId]/BoardEditBody.tsx b/src/app/(main)/boards/[boardId]/BoardEditBody.tsx index ad94800dd..e7fb5ee1b 100644 --- a/src/app/(main)/boards/[boardId]/BoardEditBody.tsx +++ b/src/app/(main)/boards/[boardId]/BoardEditBody.tsx @@ -110,8 +110,8 @@ export function BoardEditBody({ requiresBoardWebsite = true }: { requiresBoardWe const minHeight = (rows.length || 1) * MAX_ROW_HEIGHT + BUTTON_ROW_HEIGHT; return ( - - + + {rows.map((row, index) => ( {items.map(item => ( diff --git a/src/app/(main)/settings/preferences/TimezoneSetting.tsx b/src/app/(main)/settings/preferences/TimezoneSetting.tsx index f206a6e4f..765d37608 100644 --- a/src/app/(main)/settings/preferences/TimezoneSetting.tsx +++ b/src/app/(main)/settings/preferences/TimezoneSetting.tsx @@ -29,7 +29,7 @@ export function TimezoneSetting() { allowSearch={true} onSearch={setSearch} onOpenChange={handleOpen} - listProps={{ style: { maxHeight: 300 } }} + maxHeight={480} style={{ minWidth: '250px' }} > {items.map((item: any) => ( diff --git a/src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx b/src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx index 4b9053d51..89b14080b 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx @@ -1,5 +1,6 @@ import { Column, Grid, Icon, Row, Text } from '@umami/react-zen'; import type { ReactNode } from 'react'; +import { differenceInCalendarDays } from 'date-fns'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { Panel } from '@/components/common/Panel'; import { useLocale, useMessages, useResultQuery } from '@/components/hooks'; @@ -45,8 +46,6 @@ export function Retention({ websiteId, days = DAYS, startDate, endDate }: Retent return arr; }, []) || []; - const totalDays = rows.length; - return ( {data && ( @@ -84,6 +83,7 @@ export function Retention({ websiteId, days = DAYS, startDate, endDate }: Retent ))} {rows.map(({ date, visitors, records }: any, rowIndex: number) => { + const maxDay = differenceInCalendarDays(endDate, new Date(date)); return ( {days.map(day => { - if (totalDays - rowIndex < day) { - return null; - } - const percentage = records.filter(a => a.day === day)[0]?.percentage; + if (day > maxDay) return null; + const percentage = records.find(a => a.day === day)?.percentage; return ( {percentage ? `${Number(percentage).toFixed(2)}%` : ''} diff --git a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx index 1739cb4c1..642e9fe22 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx @@ -31,7 +31,7 @@ export function WebsiteHeader({ titleHref={allowLink ? renderUrl(`/websites/${website.id}`, false) : undefined} > - + {showActions && ( diff --git a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx index 3a07f9e66..683dcd493 100644 --- a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx +++ b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx @@ -154,10 +154,9 @@ export function CompareTables({ websiteId }: { websiteId: string }) { + - {events?.map(p => ( - - {p} - - ))} - - + + + + + + + + {properties.map((field: { propertyName: string }) => ( + + {field.propertyName} + + ))} + + + + {eventName && ( + + + + )} )} + {eventName && ( + + )} {eventName && propertyName && ( - + + {(selectedProperty?.dataType === DATA_TYPE.string || + selectedProperty?.dataType === DATA_TYPE.boolean) && ( + + )} + {selectedProperty?.dataType === DATA_TYPE.number && ( + + )} + {selectedProperty?.dataType === DATA_TYPE.date && ( + + )} + {selectedProperty?.dataType === DATA_TYPE.array && ( + + )} + + )} + {eventName && ( + + + )} ); } - -const EventValues = ({ websiteId, eventName, propertyName }) => { - const { - data: values, - isLoading, - isFetching, - error, - } = useEventDataValuesQuery(websiteId, eventName, propertyName); - - const propertySum = useMemo(() => { - return values?.reduce((sum, { total }) => sum + total, 0) ?? 0; - }, [values]); - - const chartData = useMemo(() => { - if (!propertyName || !values) return null; - return { - labels: values.map(({ value }) => value), - datasets: [ - { - data: values.map(({ total }) => total), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - }; - }, [propertyName, values]); - - const tableData = useMemo(() => { - if (!propertyName || !values || propertySum === 0) return []; - return values.map(({ value, total }) => ({ - label: value, - count: total, - percent: 100 * (total / propertySum), - })); - }, [propertyName, values, propertySum]); - - return ( - - {values && ( - - - - - )} - - ); -}; diff --git a/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx index 5f5ab82a8..f359b9cb0 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx @@ -87,17 +87,21 @@ export function EventsPage({ websiteId }) { })} - - handleSelect(key)}> + + handleSelect(key)} + style={{ minWidth: 0, width: '100%' }} + > {t(labels.chart)} {t(labels.activity)} {t(labels.properties)} - + - + @@ -111,7 +115,7 @@ export function EventsPage({ websiteId }) { /> - + diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx index 1bfa79ccd..17daaeed9 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx @@ -1,7 +1,7 @@ import { Column, Heading, Row, SearchField, Text } from '@umami/react-zen'; import Link from '@/components/common/Link'; import { useMemo, useState } from 'react'; -import { FixedSizeList } from 'react-window'; +import { List, type RowComponentProps } from 'react-window'; import { SessionModal } from '@/app/(main)/websites/[websiteId]/sessions/SessionModal'; import { useFormat } from '@/components//hooks/useFormat'; import { Avatar } from '@/components/common/Avatar'; @@ -121,7 +121,7 @@ export function RealtimeLog({ data }: { data: any }) { } }; - const TableRow = ({ index, style }) => { + const TableRow = ({ index, style, logs }: RowComponentProps<{ logs: any[] }>) => { const row = logs[index]; return ( @@ -195,9 +195,14 @@ export function RealtimeLog({ data }: { data: any }) { {logs?.length === 0 && } {logs?.length > 0 && ( - - {TableRow} - + )} diff --git a/src/app/(main)/websites/[websiteId]/session-data/SessionDataPivotTable.tsx b/src/app/(main)/websites/[websiteId]/session-data/SessionDataPivotTable.tsx new file mode 100644 index 000000000..c7c3716bc --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/session-data/SessionDataPivotTable.tsx @@ -0,0 +1,143 @@ +'use client'; +import { Column, DataColumn, DataTable, Row, Text } from '@umami/react-zen'; +import { useMemo } from 'react'; +import { Avatar } from '@/components/common/Avatar'; +import { DateDistance } from '@/components/common/DateDistance'; +import { Empty } from '@/components/common/Empty'; +import Link from '@/components/common/Link'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { Pager } from '@/components/common/Pager'; +import { + useMessages, + useMobile, + useNavigation, + useSessionDataPivotQuery, +} from '@/components/hooks'; +import type { PropertyFilter } from '@/lib/types'; + +export function SessionDataPivotTable({ + websiteId, + propertyName, + propertyKeys: providedPropertyKeys, + propertyFilters = [], +}: { + websiteId: string; + propertyName: string; + propertyKeys?: string[]; + propertyFilters?: PropertyFilter[]; +}) { + const { t, labels } = useMessages(); + const { router, updateParams } = useNavigation(); + const { isMobile } = useMobile(); + + const pivotQuery = useSessionDataPivotQuery(websiteId, propertyName, propertyFilters); + + const propertyKeys = useMemo(() => { + if (providedPropertyKeys) return providedPropertyKeys; + return []; + }, [providedPropertyKeys]); + + const tableMinWidth = useMemo(() => `${72 + 220 + 180 + propertyKeys.length * 160}px`, [propertyKeys.length]); + + const tableData = useMemo(() => { + if (!pivotQuery.data?.data) return []; + + return pivotQuery.data.data.map( + (row: { + sessionId: string; + distinctId: string; + createdAt: string; + propertyKeys: string[]; + propertyValues: string[]; + }) => { + const flat: Record = { + sessionId: row.sessionId, + distinctId: row.distinctId, + createdAt: row.createdAt, + }; + + row.propertyKeys.forEach((key, i) => { + flat[key] = row.propertyValues[i] ?? ''; + }); + + return flat; + }, + ); + }, [pivotQuery.data]); + + const tableQuery = useMemo( + () => (pivotQuery.data ? { ...pivotQuery.data, data: tableData } : undefined), + [pivotQuery.data, tableData], + ); + + const showPager = tableQuery && tableQuery.count > tableQuery.pageSize; + + const handlePageChange = (page: number) => { + router.push(updateParams({ page })); + }; + + const renderTruncatedText = (value: string) => ( + + + {value} + + + ); + + const renderTable = (displayMode: 'cards' | 'table') => ( + + + {(row: any) => ( + + + + )} + + {propertyKeys.map(key => ( + + {(row: any) => renderTruncatedText(row[key] ?? '')} + + ))} + + {(row: any) => renderTruncatedText(row.distinctId || '')} + + + {(row: any) => } + + + ); + + return ( + + } + > + + {isMobile ? ( + renderTable('cards') + ) : ( +
+
+ {renderTable('table')} +
+
+ )} + {showPager && tableQuery && ( + + + + )} +
+
+
+ ); +} diff --git a/src/app/(main)/websites/[websiteId]/session-data/SessionPropertyChart.tsx b/src/app/(main)/websites/[websiteId]/session-data/SessionPropertyChart.tsx new file mode 100644 index 000000000..b175908df --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/session-data/SessionPropertyChart.tsx @@ -0,0 +1,136 @@ +'use client'; +import { DistributionBarChart } from '@/components/charts/DistributionBarChart'; +import { Empty } from '@/components/common/Empty'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { useMessages, useMobile, useSessionDataActivityStatsQuery } from '@/components/hooks'; +import { formatLongNumber, formatShortTime } from '@/lib/format'; +import type { PropertyFilter } from '@/lib/types'; +import { Column, DataColumn, DataTable, Grid, Row, Text } from '@umami/react-zen'; +import { useMemo } from 'react'; + +export function SessionPropertyChart({ + websiteId, + propertyName, + propertyFilters = [], +}: { + websiteId: string; + propertyName: string; + propertyFilters?: PropertyFilter[]; +}) { + const statsQuery = useSessionDataActivityStatsQuery(websiteId, propertyName, propertyFilters); + const rows = statsQuery.data ?? []; + const { t, labels } = useMessages(); + const { isPhone } = useMobile(); + const activeTable = useMemo(() => rows.filter(row => row.activity > 0).slice(0, 10), [rows]); + const chartData = useMemo( + () => + activeTable.map(row => ({ + label: row.label, + values: { + sessions: row.sessions, + visits: row.visits, + views: row.views, + events: row.events, + }, + })), + [activeTable], + ); + + return ( + + + + {chartData.length ? ( + + {t(labels.activityByProperty)} + row.label)} + datasets={[ + { + label: t(labels.visitors), + values: chartData.map(row => row.values.sessions), + backgroundColor: 'rgba(59, 130, 246, 0.80)', + }, + { + label: t(labels.visits), + values: chartData.map(row => row.values.visits), + backgroundColor: 'rgba(16, 185, 129, 0.80)', + }, + { + label: t(labels.views), + values: chartData.map(row => row.values.views), + backgroundColor: 'rgba(245, 158, 11, 0.80)', + }, + { + label: t(labels.events), + values: chartData.map(row => row.values.events), + backgroundColor: 'rgba(244, 114, 182, 0.80)', + }, + ]} + stacked={true} + /> + + ) : ( + + )} + + + + + {activeTable.length === 0 ? ( + + ) : isPhone ? ( + + + + {row => ( + + + {row.label} + + + )} + + + + ) : ( + + + + + {row => ( + + + {row.label} + + + )} + + + {row => formatLongNumber(row.sessions)} + + + {row => formatLongNumber(row.visits)} + + + {row => formatLongNumber(row.views)} + + + {row => formatLongNumber(row.events)} + + + {row => + formatShortTime(Math.abs(~~Number(row.totaltime)), ['h', 'm', 's'], ' ') + } + + + + + )} + + + + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx index 6d21750ac..56643d2d8 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx @@ -1,21 +1,58 @@ -import { Column, Grid, ListItem, Select } from '@umami/react-zen'; +import { Column, ComboBox, Grid, Label, ListItem, Row } from '@umami/react-zen'; import { useMemo, useState } from 'react'; -import { PieChart } from '@/components/charts/PieChart'; import { LoadingPanel } from '@/components/common/LoadingPanel'; -import { - useMessages, - useSessionDataPropertiesQuery, - useSessionDataValuesQuery, -} from '@/components/hooks'; -import { ListTable } from '@/components/metrics/ListTable'; -import { CHART_COLORS } from '@/lib/constants'; +import { useMessages, usePropertyFieldsQuery, useSessionDataPropertiesQuery } from '@/components/hooks'; +import { DATA_TYPE } from '@/lib/constants'; +import type { PropertyFilter } from '@/lib/types'; +import { PropertyChart } from '@/components/property-data/PropertyChart'; +import { PropertyDateChart } from '@/components/property-data/PropertyDateChart'; +import { PropertyFilterBar } from '@/components/property-data/PropertyFilterBar'; +import { PropertyFilterButton } from '@/components/property-data/PropertyFilterButton'; +import { PropertyNumericChart } from '@/components/property-data/PropertyNumericChart'; +import { Panel } from '@/components/common/Panel'; +import { SessionDataPivotTable } from '../session-data/SessionDataPivotTable'; +import { SessionPropertyChart } from '../session-data/SessionPropertyChart'; export function SessionProperties({ websiteId }: { websiteId: string }) { const [propertyName, setPropertyName] = useState(''); + const [propertyFilters, setPropertyFilters] = useState([]); const { t, labels } = useMessages(); - const { data, isLoading, isFetching, error } = useSessionDataPropertiesQuery(websiteId); + const { data, isLoading, isFetching, error } = usePropertyFieldsQuery('session', websiteId); + const { data: scopedData } = useSessionDataPropertiesQuery( + websiteId, + propertyName ? { selectedPropertyName: propertyName, propertyFilters } : undefined, + { enabled: !!propertyName }, + ); - const properties: string[] = data?.map(e => e.propertyName); + const properties = useMemo(() => { + if (!data) return []; + const seen = new Set(); + + return data.filter((field: { propertyName: string; dataType: number }) => { + if (seen.has(field.propertyName)) return false; + seen.add(field.propertyName); + return true; + }); + }, [data]); + + const selectedProperty = useMemo( + () => properties.find((field: { propertyName: string }) => field.propertyName === propertyName), + [properties, propertyName], + ); + const scopedProperties = useMemo(() => { + if (!scopedData) return []; + const seen = new Set(); + + return scopedData.filter((field: { propertyName: string }) => { + if (seen.has(field.propertyName)) return false; + seen.add(field.propertyName); + return true; + }); + }, [scopedData]); + const scopedPropertyKeys = useMemo( + () => scopedProperties.map((field: { propertyName: string }) => field.propertyName), + [scopedProperties], + ); return ( - + {data && ( - - + + + + {properties.map((field: { propertyName: string }) => ( + + {field.propertyName} + + ))} + + + + {propertyName && ( + + + + )} )} - {propertyName && } + {propertyName && } + {propertyName && selectedProperty?.dataType === DATA_TYPE.number && ( + + )} + {propertyName && selectedProperty?.dataType === DATA_TYPE.date && ( + + )} + {propertyName && selectedProperty?.dataType === DATA_TYPE.string && ( + + )} + {propertyName && selectedProperty?.dataType === DATA_TYPE.boolean && ( + + )} + {propertyName && selectedProperty?.dataType === DATA_TYPE.array && ( + + )} + {propertyName && ( + + + + )} ); } - -const SessionValues = ({ websiteId, propertyName }) => { - const { data, isLoading, isFetching, error } = useSessionDataValuesQuery(websiteId, propertyName); - - const propertySum = useMemo(() => { - return data?.reduce((sum, { total }) => sum + total, 0) ?? 0; - }, [data]); - - const chartData = useMemo(() => { - if (!propertyName || !data) return null; - return { - labels: data.map(({ value }) => value), - datasets: [ - { - data: data.map(({ total }) => total), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - }; - }, [propertyName, data]); - - const tableData = useMemo(() => { - if (!propertyName || !data || propertySum === 0) return []; - return data.map(({ value, total }) => ({ - label: value, - count: total, - percent: 100 * (total / propertySum), - })); - }, [propertyName, data, propertySum]); - - return ( - - {data && ( - - - - - )} - - ); -}; diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx index f891f2ad7..f7eb9a868 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx @@ -24,16 +24,20 @@ export function SessionsPage({ websiteId }) { - - + + {t(labels.activity)} {t(labels.properties)} - + - + diff --git a/src/app/api/me/websites/route.ts b/src/app/api/me/websites/route.ts index 9ec39c78d..0880f84e1 100644 --- a/src/app/api/me/websites/route.ts +++ b/src/app/api/me/websites/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json } from '@/lib/response'; import { pagingParams } from '@/lib/schema'; -import { getAllUserWebsitesIncludingTeamOwner, getUserWebsites } from '@/queries/prisma'; +import { getAllUserWebsitesIncludingTeamAccess, getUserWebsites } from '@/queries/prisma'; export async function GET(request: Request) { const schema = z.object({ @@ -19,7 +19,7 @@ export async function GET(request: Request) { const filters = await getQueryFilters(query); if (query.includeTeams) { - return json(await getAllUserWebsitesIncludingTeamOwner(auth.user.id, filters)); + return json(await getAllUserWebsitesIncludingTeamAccess(auth.user.id, filters)); } return json(await getUserWebsites(auth.user.id, filters)); diff --git a/src/app/api/users/[userId]/websites/route.ts b/src/app/api/users/[userId]/websites/route.ts index 1107d8e16..4587354fb 100644 --- a/src/app/api/users/[userId]/websites/route.ts +++ b/src/app/api/users/[userId]/websites/route.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { pagingParams, searchParams } from '@/lib/schema'; -import { getAllUserWebsitesIncludingTeamOwner, getUserWebsites } from '@/queries/prisma/website'; +import { getAllUserWebsitesIncludingTeamAccess, getUserWebsites } from '@/queries/prisma/website'; export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) { const schema = z.object({ @@ -26,7 +26,7 @@ export async function GET(request: Request, { params }: { params: Promise<{ user const filters = await getQueryFilters(query); if (query.includeTeams) { - return json(await getAllUserWebsitesIncludingTeamOwner(userId, filters)); + return json(await getAllUserWebsitesIncludingTeamAccess(userId, filters)); } return json(await getUserWebsites(userId, filters)); diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts new file mode 100644 index 000000000..59afc1e72 --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/array-series/route.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataArraySeries } from '@/queries/sql/events/getEventDataArraySeries'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const data = await getEventDataArraySeries(websiteId, eventName, propertyName, filters, eventFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts new file mode 100644 index 000000000..af071dcd9 --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/date-series/route.ts @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataDateSeries } from '@/queries/sql/events/getEventDataDateSeries'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const data = await getEventDataDateSeries(websiteId, eventName, propertyName, filters, eventFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts new file mode 100644 index 000000000..ca359251b --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-series/route.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataNumericSeries } from '@/queries/sql/events/getEventDataNumericSeries'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + propertyName: z.string(), + metric: z.enum(['sum', 'avg', 'count']).default('sum'), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, propertyName, metric, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const data = await getEventDataNumericSeries(websiteId, eventName, propertyName, metric, filters, eventFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts new file mode 100644 index 000000000..7ff49e3f5 --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/numeric-stats/route.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataNumericStats } from '@/queries/sql/events/getEventDataNumericStats'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + propertyName: z.string(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const data = await getEventDataNumericStats(websiteId, eventName, propertyName, filters, eventFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts new file mode 100644 index 000000000..37c31ad34 --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/property-series/route.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataPropertySeries } from '@/queries/sql/events/getEventDataPropertySeries'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const data = await getEventDataPropertySeries(websiteId, eventName, propertyName, filters, eventFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/event-data-pivot/route.ts b/src/app/api/websites/[websiteId]/event-data-pivot/route.ts new file mode 100644 index 000000000..048f95a6f --- /dev/null +++ b/src/app/api/websites/[websiteId]/event-data-pivot/route.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { parseEventPropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, pagingParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getEventDataPivot } from '@/queries/sql/events/getEventDataPivot'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + eventName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + ...pagingParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { eventName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const eventFilters = parseEventPropertyFilters(query); + const result = await getEventDataPivot(websiteId, eventName, filters, eventFilters); + + return json(result); +} 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..b0843427b 100644 --- a/src/app/api/websites/[websiteId]/event-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/event-data/values/route.ts @@ -14,6 +14,7 @@ export async function GET( endAt: z.coerce.number().int(), event: z.string(), propertyName: z.string(), + dataType: z.coerce.number().int().optional(), ...filterParams, }); @@ -29,12 +30,13 @@ export async function GET( return unauthorized(); } - const { propertyName } = query; + const { event: eventName, propertyName, dataType } = query; const filters = await getQueryFilters(query, websiteId); - const data = await getEventDataValues(websiteId, { + const data = await getEventDataValues(websiteId, eventName, { ...filters, propertyName, + dataType, }); return json(data); diff --git a/src/app/api/websites/[websiteId]/session-data-pivot/route.ts b/src/app/api/websites/[websiteId]/session-data-pivot/route.ts new file mode 100644 index 000000000..6bf0e2b12 --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data-pivot/route.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, pagingParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataPivot } from '@/queries/sql/sessions/getSessionDataPivot'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + ...pagingParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const result = await getSessionDataPivot(websiteId, propertyName, filters, propertyFilters); + + return json(result); +} diff --git a/src/app/api/websites/[websiteId]/session-data/array-series/route.ts b/src/app/api/websites/[websiteId]/session-data/array-series/route.ts new file mode 100644 index 000000000..5dd5b4b4a --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/array-series/route.ts @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataArraySeries } from '@/queries/sql'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const data = await getSessionDataArraySeries(websiteId, propertyName, filters, propertyFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/session-data/date-series/route.ts b/src/app/api/websites/[websiteId]/session-data/date-series/route.ts new file mode 100644 index 000000000..a607ff9ac --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/date-series/route.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataDateSeries } from '@/queries/sql'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const data = await getSessionDataDateSeries(websiteId, propertyName, filters, propertyFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts b/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts new file mode 100644 index 000000000..09cf623b6 --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/numeric-series/route.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataNumericSeries } from '@/queries/sql'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + metric: z.enum(['sum', 'avg', 'count']).default('sum'), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, metric, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const data = await getSessionDataNumericSeries(websiteId, propertyName, metric, filters, propertyFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts b/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts new file mode 100644 index 000000000..a27f1bc73 --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/numeric-stats/route.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataNumericStats } from '@/queries/sql'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const data = await getSessionDataNumericStats(websiteId, propertyName, filters, propertyFilters); + + return json(data); +} 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..61a5c13d9 100644 --- a/src/app/api/websites/[websiteId]/session-data/properties/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/properties/route.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; import { filterParams } from '@/lib/schema'; @@ -12,6 +13,7 @@ export async function GET( const schema = z.object({ startAt: z.coerce.number().int(), endAt: z.coerce.number().int(), + selectedPropertyName: z.string().optional(), ...filterParams, }); @@ -27,9 +29,16 @@ export async function GET( return unauthorized(); } - const filters = await getQueryFilters(query, websiteId); + const { selectedPropertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); - const data = await getSessionDataProperties(websiteId, filters); + const data = await getSessionDataProperties( + websiteId, + filters, + propertyFilters, + selectedPropertyName, + ); return json(data); } diff --git a/src/app/api/websites/[websiteId]/session-data/property-series/route.ts b/src/app/api/websites/[websiteId]/session-data/property-series/route.ts new file mode 100644 index 000000000..fc054e6e2 --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/property-series/route.ts @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataPropertySeries } from '@/queries/sql'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const data = await getSessionDataPropertySeries(websiteId, propertyName, filters, propertyFilters); + + return json(data); +} diff --git a/src/app/api/websites/[websiteId]/session-data/stats/route.ts b/src/app/api/websites/[websiteId]/session-data/stats/route.ts new file mode 100644 index 000000000..3a41047bb --- /dev/null +++ b/src/app/api/websites/[websiteId]/session-data/stats/route.ts @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { parsePropertyFilters } from '@/lib/params'; +import { getQueryFilters, parseRequest } from '@/lib/request'; +import { json, unauthorized } from '@/lib/response'; +import { filterParams, timezoneParam, unitParam } from '@/lib/schema'; +import { canViewWebsite } from '@/permissions'; +import { getSessionDataActivityStats } from '@/queries/sql/sessions/getSessionDataActivityStats'; + +export async function GET( + request: Request, + { params }: { params: Promise<{ websiteId: string }> }, +) { + const schema = z.object({ + startAt: z.coerce.number().int(), + endAt: z.coerce.number().int(), + propertyName: z.string(), + timezone: timezoneParam.optional(), + unit: unitParam.optional(), + ...filterParams, + }); + + const { auth, query, error } = await parseRequest(request, schema); + + if (error) { + return error(); + } + + const { websiteId } = await params; + + if (!(await canViewWebsite(auth, websiteId))) { + return unauthorized(); + } + + const { propertyName, ...rest } = query; + const filters = await getQueryFilters(rest, websiteId); + const propertyFilters = parsePropertyFilters(query); + const result = await getSessionDataActivityStats(websiteId, propertyName, filters, propertyFilters); + + return json(result); +} 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..57b27e300 100644 --- a/src/app/api/websites/[websiteId]/session-data/values/route.ts +++ b/src/app/api/websites/[websiteId]/session-data/values/route.ts @@ -13,6 +13,7 @@ export async function GET( startAt: z.coerce.number().int(), endAt: z.coerce.number().int(), propertyName: z.string().optional(), + dataType: z.coerce.number().int().optional(), ...filterParams, }); @@ -28,12 +29,13 @@ export async function GET( return unauthorized(); } - const { propertyName } = query; + const { propertyName, dataType } = query; const filters = await getQueryFilters(query, websiteId); const data = await getSessionDataValues(websiteId, { ...filters, propertyName, + dataType, }); return json(data); diff --git a/src/app/api/websites/route.ts b/src/app/api/websites/route.ts index d54aeac62..288ddfe30 100644 --- a/src/app/api/websites/route.ts +++ b/src/app/api/websites/route.ts @@ -7,7 +7,7 @@ import { json, unauthorized } from '@/lib/response'; import { pagingParams, searchParams } from '@/lib/schema'; import { canCreateTeamWebsite, canCreateWebsite } from '@/permissions'; import { createShare, createWebsite, getWebsiteCount } from '@/queries/prisma'; -import { getAllUserWebsitesIncludingTeamOwner, getUserWebsites } from '@/queries/prisma/website'; +import { getAllUserWebsitesIncludingTeamAccess, getUserWebsites } from '@/queries/prisma/website'; const CLOUD_WEBSITE_LIMIT = 3; @@ -29,7 +29,7 @@ export async function GET(request: Request) { const filters = await getQueryFilters(query); if (query.includeTeams) { - return json(await getAllUserWebsitesIncludingTeamOwner(userId, filters)); + return json(await getAllUserWebsitesIncludingTeamAccess(userId, filters)); } return json(await getUserWebsites(userId, filters)); diff --git a/src/components/charts/DistributionBarChart.tsx b/src/components/charts/DistributionBarChart.tsx new file mode 100644 index 000000000..90a668c83 --- /dev/null +++ b/src/components/charts/DistributionBarChart.tsx @@ -0,0 +1,172 @@ +'use client'; +import { useTheme } from '@umami/react-zen'; +import { memo, useCallback, useMemo, useState } from 'react'; +import { Chart } from '@/components/charts/Chart'; +import { ChartTooltip } from '@/components/charts/ChartTooltip'; +import { renderNumberLabels } from '@/lib/charts'; +import { getThemeColors } from '@/lib/colors'; +import { formatLongNumber } from '@/lib/format'; + +interface DistributionDatum { + label: string; + count: number; +} + +interface DistributionDataset { + label: string; + values: number[]; + backgroundColor: string; + borderColor?: string; +} + +interface TooltipState { + title: string; + color?: string; + value: string; +} + +export interface DistributionBarChartProps { + data?: DistributionDatum[]; + labels?: string[]; + datasets?: DistributionDataset[]; + height?: string; + backgroundColor?: string; + borderColor?: string; + stacked?: boolean; + horizontal?: boolean; +} + +function DistributionBarChartComponent({ + data, + labels, + datasets, + height = '320px', + backgroundColor = 'rgba(59, 130, 246, 0.75)', + borderColor = 'rgba(59, 130, 246, 0.95)', + stacked = false, + horizontal = true, +}: DistributionBarChartProps) { + const [tooltip, setTooltip] = useState(null); + const { theme } = useTheme(); + const { colors } = useMemo(() => getThemeColors(theme), [theme]); + + const chartData = useMemo(() => { + if (datasets?.length && labels?.length) { + return { + labels, + datasets: datasets.map(dataset => ({ + label: dataset.label, + data: dataset.values, + backgroundColor: dataset.backgroundColor, + borderColor: dataset.borderColor || dataset.backgroundColor, + borderWidth: 1, + })), + }; + } + + return { + labels: (data || []).map(item => item.label), + datasets: [ + { + label: '', + data: (data || []).map(item => item.count), + backgroundColor, + borderColor, + borderWidth: 1, + }, + ], + }; + }, [data, labels, datasets, backgroundColor, borderColor]); + + const chartOptions = useMemo( + () => ({ + indexAxis: horizontal ? ('y' as const) : ('x' as const), + scales: { + x: { + type: horizontal ? ('linear' as const) : ('category' as const), + min: horizontal ? 0 : undefined, + beginAtZero: horizontal ? true : undefined, + stacked, + grid: { + display: horizontal ? true : false, + color: colors.chart.line, + }, + border: { + color: colors.chart.line, + }, + ticks: { + color: colors.chart.text, + autoSkip: horizontal ? undefined : true, + maxRotation: horizontal ? undefined : 0, + callback: horizontal + ? (tickValue: string | number) => renderNumberLabels(String(tickValue)) + : (tickValue: string | number) => chartData.labels?.[Number(tickValue)] || '', + }, + }, + y: { + type: horizontal ? ('category' as const) : ('linear' as const), + min: horizontal ? undefined : 0, + beginAtZero: horizontal ? undefined : true, + stacked, + grid: { + display: horizontal ? false : true, + color: colors.chart.line, + }, + border: { + color: colors.chart.line, + }, + ticks: { + color: colors.chart.text, + callback: horizontal + ? (tickValue: string | number) => chartData.labels?.[Number(tickValue)] || '' + : (tickValue: string | number) => renderNumberLabels(String(tickValue)), + }, + }, + }, + }), + [chartData.labels, colors, horizontal, stacked], + ); + + const handleTooltip = useCallback(({ tooltip }: { tooltip: any }) => { + const { opacity, labelColors, dataPoints } = tooltip; + const point = dataPoints?.[0]; + const nextTooltip = opacity + ? { + title: (point?.label ?? '').toString(), + color: labelColors?.[0]?.backgroundColor, + value: `${formatLongNumber( + Number(horizontal ? point?.raw?.x ?? point?.raw ?? 0 : point?.raw?.y ?? point?.raw ?? 0), + )}${point?.dataset?.label ? ` ${point.dataset.label}` : ''}`, + } + : null; + + setTooltip(prev => { + if ( + prev?.title === nextTooltip?.title && + prev?.color === nextTooltip?.color && + prev?.value === nextTooltip?.value + ) { + return prev; + } + + return nextTooltip; + }); + }, [horizontal]); + + return ( + <> + + {tooltip && } + + ); +} + +export const DistributionBarChart = memo(DistributionBarChartComponent); + +DistributionBarChart.displayName = 'DistributionBarChart'; diff --git a/src/components/common/AnimatedDiv.tsx b/src/components/common/AnimatedDiv.tsx index f9948971a..4832ac32b 100644 --- a/src/components/common/AnimatedDiv.tsx +++ b/src/components/common/AnimatedDiv.tsx @@ -1,3 +1,3 @@ -import { type AnimatedComponent, animated } from '@react-spring/web'; +import { motion } from 'motion/react'; -export const AnimatedDiv: AnimatedComponent = animated.div; +export const AnimatedDiv = motion.div; diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index 1b27b684a..a5dfd589f 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -17,10 +17,9 @@ export * from './queries/useBoardsQuery'; export * from './queries/useDashboardQuery'; export * from './queries/useDateRangeQuery'; export * from './queries/useDeleteQuery'; -export * from './queries/useEventDataEventsQuery'; +export * from './queries/useEventDataPivotQuery'; export * from './queries/useEventDataPropertiesQuery'; export * from './queries/useEventDataQuery'; -export * from './queries/useEventDataValuesQuery'; export * from './queries/useLinkQuery'; export * from './queries/useLinkSharesQuery'; export * from './queries/useLinksQuery'; @@ -28,6 +27,13 @@ export * from './queries/useLoginQuery'; export * from './queries/usePixelQuery'; export * from './queries/usePixelSharesQuery'; export * from './queries/usePixelsQuery'; +export * from './queries/usePropertyArraySeriesQuery'; +export * from './queries/usePropertyDateSeriesQuery'; +export * from './queries/usePropertyFieldsQuery'; +export * from './queries/usePropertyNumericSeriesQuery'; +export * from './queries/usePropertyNumericStatsQuery'; +export * from './queries/usePropertySeriesQuery'; +export * from './queries/usePropertyValuesQuery'; export * from './queries/useRealtimeQuery'; export * from './queries/useReplayQuery'; export * from './queries/useReplaySavedQuery'; @@ -39,7 +45,9 @@ export * from './queries/useRevenueSessionsQuery'; export * from './queries/useSavedReplaysQuery'; export * from './queries/useSessionActivityQuery'; export * from './queries/useSessionDataPropertiesQuery'; +export * from './queries/useSessionDataPivotQuery'; export * from './queries/useSessionDataQuery'; +export * from './queries/useSessionDataActivityStatsQuery'; export * from './queries/useSessionDataValuesQuery'; export * from './queries/useSessionReplaysQuery'; export * from './queries/useShareTokenQuery'; diff --git a/src/components/hooks/queries/useActiveUsersQuery.ts b/src/components/hooks/queries/useActiveUsersQuery.ts index 42867c19d..7190a2f9c 100644 --- a/src/components/hooks/queries/useActiveUsersQuery.ts +++ b/src/components/hooks/queries/useActiveUsersQuery.ts @@ -1,7 +1,7 @@ import type { ReactQueryOptions } from '@/lib/types'; import { useApi } from '../useApi'; -export function useActyiveUsersQuery(websiteId: string, options?: ReactQueryOptions) { +export function useActiveUsersQuery(websiteId: string, options?: ReactQueryOptions) { const { get, useQuery } = useApi(); return useQuery({ queryKey: ['websites:active', websiteId], diff --git a/src/components/hooks/queries/useEventDataEventsQuery.ts b/src/components/hooks/queries/useEventDataEventsQuery.ts deleted file mode 100644 index 1401989f3..000000000 --- a/src/components/hooks/queries/useEventDataEventsQuery.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ReactQueryOptions } from '@/lib/types'; -import { useApi } from '../useApi'; -import { useDateParameters } from '../useDateParameters'; -import { useFilterParameters } from '../useFilterParameters'; - -export function useEventDataEventsQuery(websiteId: string, options?: ReactQueryOptions) { - const { get, useQuery } = useApi(); - const { startAt, endAt, unit, timezone } = useDateParameters(); - const filters = useFilterParameters(); - - return useQuery({ - queryKey: [ - 'websites:event-data:events', - { websiteId, startAt, endAt, unit, timezone, ...filters }, - ], - queryFn: () => - get(`/websites/${websiteId}/event-data/events`, { - startAt, - endAt, - unit, - timezone, - ...filters, - }), - enabled: !!websiteId, - ...options, - }); -} diff --git a/src/components/hooks/queries/useEventDataPivotQuery.ts b/src/components/hooks/queries/useEventDataPivotQuery.ts new file mode 100644 index 000000000..e9f689ac7 --- /dev/null +++ b/src/components/hooks/queries/useEventDataPivotQuery.ts @@ -0,0 +1,35 @@ +import { serializeEventPropertyFilters } from '@/lib/params'; +import type { EventPropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; + +export function useEventDataPivotQuery( + websiteId: string, + eventName: string, + eventFilters: EventPropertyFilter[] = [], + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters(); + + return useQuery({ + queryKey: [ + 'websites:event-data-pivot', + { websiteId, eventName, eventFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get(`/websites/${websiteId}/event-data-pivot`, { + eventName, + startAt, + endAt, + unit, + timezone, + ...serializeEventPropertyFilters(eventFilters), + ...params, + }), + enabled: !!(websiteId && eventName), + ...options, + }); +} diff --git a/src/components/hooks/queries/useEventDataPropertiesQuery.ts b/src/components/hooks/queries/useEventDataPropertiesQuery.ts index dfa6e9295..ef921824e 100644 --- a/src/components/hooks/queries/useEventDataPropertiesQuery.ts +++ b/src/components/hooks/queries/useEventDataPropertiesQuery.ts @@ -6,7 +6,7 @@ import { useFilterParameters } from '../useFilterParameters'; export function useEventDataPropertiesQuery(websiteId: string, options?: ReactQueryOptions) { const { get, useQuery } = useApi(); const { startAt, endAt, unit, timezone } = useDateParameters(); - const filters = useFilterParameters(); + const filters = useFilterParameters({ includePagination: false }); return useQuery({ queryKey: [ diff --git a/src/components/hooks/queries/useEventStatsQuery.ts b/src/components/hooks/queries/useEventStatsQuery.ts index b3ca60eaa..6c61e75f5 100644 --- a/src/components/hooks/queries/useEventStatsQuery.ts +++ b/src/components/hooks/queries/useEventStatsQuery.ts @@ -26,7 +26,7 @@ export function useEventStatsQuery( ) { const { get, useQuery } = useApi(); const { startAt, endAt } = useDateParameters(); - const filters = useFilterParameters(); + const filters = useFilterParameters({ includePagination: false }); return useQuery({ queryKey: ['websites:events:stats', { websiteId, startAt, endAt, ...filters }], diff --git a/src/components/hooks/queries/usePropertyArraySeriesQuery.ts b/src/components/hooks/queries/usePropertyArraySeriesQuery.ts new file mode 100644 index 000000000..fd4b8a42c --- /dev/null +++ b/src/components/hooks/queries/usePropertyArraySeriesQuery.ts @@ -0,0 +1,44 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { EventDataSeriesPoint, PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertyArraySeriesQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:array-series`, + { websiteId, propertyName, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data-pivot/array-series` + : `/websites/${websiteId}/session-data/array-series`, + { + ...(source === 'event' ? { eventName } : {}), + propertyName, + startAt, + endAt, + unit, + timezone, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertyDateSeriesQuery.ts b/src/components/hooks/queries/usePropertyDateSeriesQuery.ts new file mode 100644 index 000000000..4c34c0400 --- /dev/null +++ b/src/components/hooks/queries/usePropertyDateSeriesQuery.ts @@ -0,0 +1,43 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { EventDataDateSeriesPoint, PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertyDateSeriesQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:date-series`, + { websiteId, propertyName, eventName, propertyFilters, startAt, endAt, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data-pivot/date-series` + : `/websites/${websiteId}/session-data/date-series`, + { + ...(source === 'event' ? { eventName } : {}), + propertyName, + startAt, + endAt, + timezone, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertyFieldsQuery.ts b/src/components/hooks/queries/usePropertyFieldsQuery.ts new file mode 100644 index 000000000..48cfea9e7 --- /dev/null +++ b/src/components/hooks/queries/usePropertyFieldsQuery.ts @@ -0,0 +1,40 @@ +import type { ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; + +export type PropertyDataSource = 'event' | 'session'; + +export function usePropertyFieldsQuery( + source: PropertyDataSource, + websiteId: string, + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:fields`, + { websiteId, eventName, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data/fields` + : `/websites/${websiteId}/session-data/properties`, + { + ...(source === 'event' ? { event: eventName } : {}), + startAt, + endAt, + unit, + timezone, + ...params, + }, + ), + enabled: !!(websiteId && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertyNumericSeriesQuery.ts b/src/components/hooks/queries/usePropertyNumericSeriesQuery.ts new file mode 100644 index 000000000..ffe5b18b7 --- /dev/null +++ b/src/components/hooks/queries/usePropertyNumericSeriesQuery.ts @@ -0,0 +1,46 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertyNumericSeriesQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:numeric-series`, + { websiteId, propertyName, metric, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data-pivot/numeric-series` + : `/websites/${websiteId}/session-data/numeric-series`, + { + ...(source === 'event' ? { eventName } : {}), + propertyName, + metric, + startAt, + endAt, + unit, + timezone, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertyNumericStatsQuery.ts b/src/components/hooks/queries/usePropertyNumericStatsQuery.ts new file mode 100644 index 000000000..01cc48568 --- /dev/null +++ b/src/components/hooks/queries/usePropertyNumericStatsQuery.ts @@ -0,0 +1,43 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { EventDataNumericStats, PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertyNumericStatsQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:numeric-stats`, + { websiteId, propertyName, eventName, propertyFilters, startAt, endAt, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data-pivot/numeric-stats` + : `/websites/${websiteId}/session-data/numeric-stats`, + { + ...(source === 'event' ? { eventName } : {}), + propertyName, + startAt, + endAt, + timezone, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertySeriesQuery.ts b/src/components/hooks/queries/usePropertySeriesQuery.ts new file mode 100644 index 000000000..3df8af796 --- /dev/null +++ b/src/components/hooks/queries/usePropertySeriesQuery.ts @@ -0,0 +1,44 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { EventDataSeriesPoint, PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertySeriesQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:property-series`, + { websiteId, propertyName, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data-pivot/property-series` + : `/websites/${websiteId}/session-data/property-series`, + { + ...(source === 'event' ? { eventName } : {}), + propertyName, + startAt, + endAt, + unit, + timezone, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/usePropertyValuesQuery.ts b/src/components/hooks/queries/usePropertyValuesQuery.ts new file mode 100644 index 000000000..131620fae --- /dev/null +++ b/src/components/hooks/queries/usePropertyValuesQuery.ts @@ -0,0 +1,46 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; +import type { PropertyDataSource } from './usePropertyFieldsQuery'; + +export function usePropertyValuesQuery( + source: PropertyDataSource, + websiteId: string, + propertyName: string, + dataType?: number, + propertyFilters: PropertyFilter[] = [], + eventName?: string, + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + `websites:${source}-data:values`, + { websiteId, propertyName, dataType, eventName, propertyFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get( + source === 'event' + ? `/websites/${websiteId}/event-data/values` + : `/websites/${websiteId}/session-data/values`, + { + ...(source === 'event' ? { event: eventName } : {}), + startAt, + endAt, + unit, + timezone, + propertyName, + dataType, + ...serializePropertyFilters(propertyFilters), + ...params, + }, + ), + enabled: !!(websiteId && propertyName && (source === 'session' || eventName)), + ...options, + }); +} diff --git a/src/components/hooks/queries/useResultQuery.ts b/src/components/hooks/queries/useResultQuery.ts index 1828e594a..785b05694 100644 --- a/src/components/hooks/queries/useResultQuery.ts +++ b/src/components/hooks/queries/useResultQuery.ts @@ -11,7 +11,7 @@ export function useResultQuery( const { websiteId, ...parameters } = params; const { post, useQuery } = useApi(); const { startDate, endDate, timezone, unit } = useDateParameters(); - const filters = useFilterParameters(); + const filters = useFilterParameters({ includePagination: false }); return useQuery({ queryKey: [ diff --git a/src/components/hooks/queries/useSessionDataActivityStatsQuery.ts b/src/components/hooks/queries/useSessionDataActivityStatsQuery.ts new file mode 100644 index 000000000..72ca11fd5 --- /dev/null +++ b/src/components/hooks/queries/useSessionDataActivityStatsQuery.ts @@ -0,0 +1,35 @@ +import { serializePropertyFilters } from '@/lib/params'; +import type { PropertyFilter, ReactQueryOptions } from '@/lib/types'; +import { useApi } from '../useApi'; +import { useDateParameters } from '../useDateParameters'; +import { useFilterParameters } from '../useFilterParameters'; + +export function useSessionDataActivityStatsQuery( + websiteId: string, + propertyName: string, + propertyFilters: PropertyFilter[] = [], + options?: ReactQueryOptions, +) { + const { get, useQuery } = useApi(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const params = useFilterParameters({ includePagination: false }); + + return useQuery({ + queryKey: [ + 'websites:session-data:activity-stats', + { websiteId, propertyName, propertyFilters, startAt, endAt, unit, timezone, ...params }, + ], + queryFn: () => + get(`/websites/${websiteId}/session-data/stats`, { + startAt, + endAt, + unit, + timezone, + propertyName, + ...serializePropertyFilters(propertyFilters), + ...params, + }), + enabled: !!(websiteId && propertyName), + ...options, + }); +} diff --git a/src/components/hooks/queries/useEventDataValuesQuery.ts b/src/components/hooks/queries/useSessionDataPivotQuery.ts similarity index 50% rename from src/components/hooks/queries/useEventDataValuesQuery.ts rename to src/components/hooks/queries/useSessionDataPivotQuery.ts index db2a2d7e0..db5fecccf 100644 --- a/src/components/hooks/queries/useEventDataValuesQuery.ts +++ b/src/components/hooks/queries/useSessionDataPivotQuery.ts @@ -1,32 +1,33 @@ -import type { ReactQueryOptions } from '@/lib/types'; +import { serializePropertyFilters } from '@/lib/params'; +import type { PropertyFilter, ReactQueryOptions } from '@/lib/types'; import { useApi } from '../useApi'; import { useDateParameters } from '../useDateParameters'; import { useFilterParameters } from '../useFilterParameters'; -export function useEventDataValuesQuery( +export function useSessionDataPivotQuery( websiteId: string, - event: string, propertyName: string, + propertyFilters: PropertyFilter[] = [], options?: ReactQueryOptions, ) { const { get, useQuery } = useApi(); const { startAt, endAt, unit, timezone } = useDateParameters(); - const filters = useFilterParameters(); + const params = useFilterParameters(); - return useQuery({ + return useQuery({ queryKey: [ - 'websites:event-data:values', - { websiteId, startAt, endAt, unit, timezone, ...filters, event, propertyName }, + 'websites:session-data-pivot', + { websiteId, propertyName, propertyFilters, startAt, endAt, unit, timezone, ...params }, ], queryFn: () => - get(`/websites/${websiteId}/event-data/values`, { + get(`/websites/${websiteId}/session-data-pivot`, { startAt, endAt, unit, timezone, - ...filters, - event, propertyName, + ...serializePropertyFilters(propertyFilters), + ...params, }), enabled: !!(websiteId && propertyName), ...options, diff --git a/src/components/hooks/queries/useSessionDataPropertiesQuery.ts b/src/components/hooks/queries/useSessionDataPropertiesQuery.ts index ac651bb96..fa52ae302 100644 --- a/src/components/hooks/queries/useSessionDataPropertiesQuery.ts +++ b/src/components/hooks/queries/useSessionDataPropertiesQuery.ts @@ -1,17 +1,36 @@ import type { ReactQueryOptions } from '@/lib/types'; +import { serializePropertyFilters } from '@/lib/params'; +import type { PropertyFilter } from '@/lib/types'; import { useApi } from '../useApi'; import { useDateParameters } from '../useDateParameters'; import { useFilterParameters } from '../useFilterParameters'; -export function useSessionDataPropertiesQuery(websiteId: string, options?: ReactQueryOptions) { +export function useSessionDataPropertiesQuery( + websiteId: string, + params?: { + selectedPropertyName?: string; + propertyFilters?: PropertyFilter[]; + }, + options?: ReactQueryOptions, +) { const { get, useQuery } = useApi(); const { startAt, endAt, unit, timezone } = useDateParameters(); - const filters = useFilterParameters(); + const filters = useFilterParameters({ includePagination: false }); + const { selectedPropertyName, propertyFilters = [] } = params || {}; return useQuery({ queryKey: [ 'websites:session-data:properties', - { websiteId, startAt, endAt, unit, timezone, ...filters }, + { + websiteId, + selectedPropertyName, + propertyFilters, + startAt, + endAt, + unit, + timezone, + ...filters, + }, ], queryFn: () => get(`/websites/${websiteId}/session-data/properties`, { @@ -19,6 +38,8 @@ export function useSessionDataPropertiesQuery(websiteId: string, options?: React endAt, unit, timezone, + selectedPropertyName, + ...serializePropertyFilters(propertyFilters), ...filters, }), enabled: !!websiteId, diff --git a/src/components/hooks/useFilterParameters.ts b/src/components/hooks/useFilterParameters.ts index 3579bef95..24211c386 100644 --- a/src/components/hooks/useFilterParameters.ts +++ b/src/components/hooks/useFilterParameters.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { FILTER_COLUMNS } from '@/lib/constants'; import { useNavigation } from './useNavigation'; -export function useFilterParameters() { +export function useFilterParameters({ includePagination = true }: { includePagination?: boolean } = {}) { const { query } = useNavigation(); return useMemo(() => { @@ -15,15 +15,20 @@ export function useFilterParameters() { } } - return { + const params = { ...filterParams, search: query.search, segment: query.segment, cohort: query.cohort, excludeBounce: query.excludeBounce, match: query.match, - page: query.page, - pageSize: query.pageSize, - }; - }, [query]); + } as Record; + + if (includePagination) { + params.page = query.page; + params.pageSize = query.pageSize; + } + + return params; + }, [query, includePagination]); } diff --git a/src/components/hooks/useTimezone.ts b/src/components/hooks/useTimezone.ts index ef2553902..497c238b2 100644 --- a/src/components/hooks/useTimezone.ts +++ b/src/components/hooks/useTimezone.ts @@ -1,4 +1,4 @@ -import { formatInTimeZone, utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz'; +import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz'; import { TIMEZONE_CONFIG, TIMEZONE_LEGACY } from '@/lib/constants'; import { getTimezone } from '@/lib/date'; import { setItem } from '@/lib/storage'; @@ -61,19 +61,19 @@ export function useTimezone() { }; const toUtc = (date: Date | string | number) => { - return zonedTimeToUtc(date, timezone); + return fromZonedTime(date, timezone); }; const fromUtc = (date: Date | string | number) => { - return utcToZonedTime(date, timezone); + return toZonedTime(date, timezone); }; const localToUtc = (date: Date | string | number) => { - return zonedTimeToUtc(date, localTimeZone); + return fromZonedTime(date, localTimeZone); }; const localFromUtc = (date: Date | string | number) => { - return utcToZonedTime(date, localTimeZone); + return toZonedTime(date, localTimeZone); }; const canonicalizeTimezone = (timezone: string): string => { diff --git a/src/components/input/BoardSelect.tsx b/src/components/input/BoardSelect.tsx index b8fbf3a6a..ac04f5429 100644 --- a/src/components/input/BoardSelect.tsx +++ b/src/components/input/BoardSelect.tsx @@ -72,12 +72,12 @@ export function BoardSelect({ ...buttonProps?.style, }, }} + maxHeight={480} listProps={{ ...listProps, renderEmptyState: listProps?.renderEmptyState || (() => ), style: { - maxHeight: 'calc(42vh - 65px)', width: 280, ...listProps?.style, }, diff --git a/src/components/input/CurrencySelect.tsx b/src/components/input/CurrencySelect.tsx index 8bad9821c..3f4a870c2 100644 --- a/src/components/input/CurrencySelect.tsx +++ b/src/components/input/CurrencySelect.tsx @@ -13,7 +13,7 @@ export function CurrencySelect({ value, onChange }) { value={value} defaultValue={value} onChange={onChange} - listProps={{ style: { maxHeight: 300 } }} + maxHeight={480} onSearch={setSearch} allowSearch > diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index ca55bbefa..4bff007ad 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -1,10 +1,9 @@ import { Dialog, ListItem, ListSeparator, Modal, Select, type SelectProps } from '@umami/react-zen'; -import { endOfYear } from 'date-fns'; import { Fragment, type Key, useState } from 'react'; import { DateDisplay } from '@/components/common/DateDisplay'; import { useMessages, useMobile } from '@/components/hooks'; import { DatePickerForm } from '@/components/metrics/DatePickerForm'; -import { parseDateRange } from '@/lib/date'; +import { getMaxSelectableDate, parseDateRange } from '@/lib/date'; export interface DateFilterProps extends SelectProps { value?: string; @@ -129,7 +128,7 @@ export function DateFilter({ startDate={startDate} endDate={endDate} minDate={new Date(2000, 0, 1)} - maxDate={endOfYear(new Date())} + maxDate={getMaxSelectableDate()} onChange={handlePickerChange} onClose={() => setShowPicker(false)} /> diff --git a/src/components/input/FilterBar.tsx b/src/components/input/FilterBar.tsx index 90be256be..d8c121222 100644 --- a/src/components/input/FilterBar.tsx +++ b/src/components/input/FilterBar.tsx @@ -14,6 +14,7 @@ import { useFilters, useFormat, useMessages, + useMobile, useNavigation, useWebsiteSegmentQuery, } from '@/components/hooks'; @@ -22,6 +23,7 @@ import { isSearchOperator } from '@/lib/params'; export function FilterBar({ websiteId }: { websiteId?: string }) { const { t, labels } = useMessages(); + const { isMobile } = useMobile(); const { formatValue } = useFormat(); const { router, @@ -58,8 +60,9 @@ export function FilterBar({ websiteId }: { websiteId?: string }) { justifyContent="space-between" padding="2" backgroundColor="surface-sunken" + wrap="wrap" > - + {segment && !isLoading && ( )} - - + + {({ close }) => { return ; }} @@ -149,7 +163,7 @@ const FilterItem = ({ name, label, operator, value, onRemove }) => { theme="dark" > - + {label} diff --git a/src/components/input/LinkSelect.tsx b/src/components/input/LinkSelect.tsx index 34c864e08..dc041bd02 100644 --- a/src/components/input/LinkSelect.tsx +++ b/src/components/input/LinkSelect.tsx @@ -76,12 +76,12 @@ export function LinkSelect({ ...buttonProps?.style, }, }} + maxHeight={480} listProps={{ ...listProps, renderEmptyState: listProps?.renderEmptyState || (() => ), style: { - maxHeight: 'calc(42vh - 65px)', width: 280, ...listProps?.style, }, diff --git a/src/components/input/PixelSelect.tsx b/src/components/input/PixelSelect.tsx index 5ad68f307..c2ba711b4 100644 --- a/src/components/input/PixelSelect.tsx +++ b/src/components/input/PixelSelect.tsx @@ -76,12 +76,12 @@ export function PixelSelect({ ...buttonProps?.style, }, }} + maxHeight={480} listProps={{ ...listProps, renderEmptyState: listProps?.renderEmptyState || (() => ), style: { - maxHeight: 'calc(42vh - 65px)', width: 280, ...listProps?.style, }, diff --git a/src/components/input/SegmentSaveButton.tsx b/src/components/input/SegmentSaveButton.tsx index 9acf3ded8..520d5eeaa 100644 --- a/src/components/input/SegmentSaveButton.tsx +++ b/src/components/input/SegmentSaveButton.tsx @@ -1,10 +1,11 @@ import { Button, Dialog, DialogTrigger, Icon, Modal, Text } from '@umami/react-zen'; import { SegmentEditForm } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditForm'; -import { useMessages } from '@/components/hooks'; +import { useMessages, useMobile } from '@/components/hooks'; import { Plus } from '@/components/icons'; export function SegmentSaveButton({ websiteId }: { websiteId: string }) { const { t, labels } = useMessages(); + const { isMobile } = useMobile(); return ( @@ -14,8 +15,18 @@ export function SegmentSaveButton({ websiteId }: { websiteId: string }) { {t(labels.segment)} - - + + {({ close }) => { return ; }} diff --git a/src/components/input/UserSelect.tsx b/src/components/input/UserSelect.tsx index bd3a766a7..65e6689fe 100644 --- a/src/components/input/UserSelect.tsx +++ b/src/components/input/UserSelect.tsx @@ -50,9 +50,9 @@ export function UserSelect({ onSearch={handleSearch} onChange={handleChange} onOpenChange={handleOpenChange} + maxHeight={480} listProps={{ renderEmptyState: () => , - style: { maxHeight: 'calc(42vh - 65px)' }, }} > {listItems.map(({ id, username }) => ( diff --git a/src/components/input/WebsiteSelect.tsx b/src/components/input/WebsiteSelect.tsx index 3fd28cdd2..90d374f19 100644 --- a/src/components/input/WebsiteSelect.tsx +++ b/src/components/input/WebsiteSelect.tsx @@ -91,12 +91,12 @@ export function WebsiteSelect({ ...buttonProps?.style, }, }} + maxHeight={480} listProps={{ ...listProps, renderEmptyState: listProps?.renderEmptyState || (() => ), style: { - maxHeight: 'calc(42vh - 65px)', width: 280, ...listProps?.style, }, diff --git a/src/components/messages.ts b/src/components/messages.ts index 5046f1904..72ce903cf 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -134,6 +134,7 @@ export const labels: Record = { thisYear: 'label.this-year', allTime: 'label.all-time', customRange: 'label.custom-range', + selectEvent: 'label.select-event', selectWebsite: 'label.select-website', selectLink: 'label.select-link', selectPixel: 'label.select-pixel', @@ -189,6 +190,8 @@ export const labels: Record = { type: 'label.type', filter: 'label.filter', filters: 'label.filters', + propertyFilter: 'label.property-filter', + activityByProperty: 'label.activity-by-property', breakdown: 'label.breakdown', true: 'label.true', false: 'label.false', diff --git a/src/components/metrics/ActiveUsers.tsx b/src/components/metrics/ActiveUsers.tsx index 2baf3357c..8f0a68c2a 100644 --- a/src/components/metrics/ActiveUsers.tsx +++ b/src/components/metrics/ActiveUsers.tsx @@ -1,18 +1,21 @@ import { StatusLight, Text } from '@umami/react-zen'; import { useMemo } from 'react'; -import { useActyiveUsersQuery, useMessages } from '@/components/hooks'; +import Link from '@/components/common/Link'; +import { useActiveUsersQuery, useMessages } from '@/components/hooks'; export function ActiveUsers({ websiteId, value, refetchInterval = 60000, + allowLink = true, }: { websiteId: string; value?: number; refetchInterval?: number; + allowLink?: boolean; }) { const { t, labels } = useMessages(); - const { data } = useActyiveUsersQuery(websiteId, { refetchInterval }); + const { data } = useActiveUsersQuery(websiteId, { refetchInterval }); const count = useMemo(() => { if (websiteId) { @@ -26,11 +29,17 @@ export function ActiveUsers({ return null; } - return ( + const content = ( {count} {t(labels.online)} ); -} + + if (!allowLink) { + return content; + } + + return {content}; +} \ No newline at end of file diff --git a/src/components/metrics/ListTable.tsx b/src/components/metrics/ListTable.tsx index f47d8ac0c..f06b7cec0 100644 --- a/src/components/metrics/ListTable.tsx +++ b/src/components/metrics/ListTable.tsx @@ -1,7 +1,7 @@ -import { config, useSpring } from '@react-spring/web'; import { Column, Grid, Row, Text } from '@umami/react-zen'; -import type { ReactNode } from 'react'; -import { FixedSizeList } from 'react-window'; +import { useSpring, useTransform } from 'motion/react'; +import { type ReactNode, useEffect } from 'react'; +import { List, type RowComponentProps } from 'react-window'; import { AnimatedDiv } from '@/components/common/AnimatedDiv'; import { Empty } from '@/components/common/Empty'; import { useMessages, useMobile } from '@/components/hooks'; @@ -62,7 +62,7 @@ export function ListTable({ ); }; - const ListTableRow = ({ index, style }) => { + const ListTableRow = ({ index, style }: RowComponentProps) => { return
{getRow(data[index], index)}
; }; @@ -82,14 +82,14 @@ export function ListTable({ {data?.length === 0 && } {virtualize && data.length > 0 ? ( - - {ListTableRow} - + ) : ( data.map(getRow) )} @@ -108,12 +108,21 @@ const AnimatedRow = ({ formatCount, isPhone, }) => { - const props = useSpring({ - width: percent, - y: !Number.isNaN(value) ? value : 0, - from: { width: 0, y: 0 }, - config: animate ? config.default : { duration: 0 }, - }); + const y = !Number.isNaN(value) ? value : 0; + const ySpring = useSpring(0, { stiffness: 170, damping: 26 }); + const widthSpring = useSpring(0, { stiffness: 170, damping: 26 }); + const yText = useTransform(ySpring, n => (formatCount ? formatCount(n) : formatLongNumber(n))); + const widthText = useTransform(widthSpring, n => `${n?.toFixed?.(0)}%`); + + useEffect(() => { + if (animate) { + ySpring.set(y); + widthSpring.set(percent); + } else { + ySpring.jump(y); + widthSpring.jump(percent); + } + }, [y, percent, animate, ySpring, widthSpring]); return ( {change} - - {formatCount ? props.y?.to(formatCount) : props.y?.to(formatLongNumber)} - + {yText}
{showPercentage && ( @@ -151,7 +158,7 @@ const AnimatedRow = ({ color="muted" paddingLeft="3" > - {props.width.to(n => `${n?.toFixed?.(0)}%`)} + {widthText}
)} diff --git a/src/components/metrics/MetricCard.tsx b/src/components/metrics/MetricCard.tsx index 24768e3f4..f7bbb0a6f 100644 --- a/src/components/metrics/MetricCard.tsx +++ b/src/components/metrics/MetricCard.tsx @@ -1,6 +1,6 @@ -import { useSpring } from '@react-spring/web'; import { Button, Column, Icon, Row, Text, Tooltip, TooltipTrigger } from '@umami/react-zen'; -import type { ReactNode } from 'react'; +import { useSpring, useTransform } from 'motion/react'; +import { type ReactNode, useEffect } from 'react'; import { AnimatedDiv } from '@/components/common/AnimatedDiv'; import { Info } from '@/components/icons'; import { ChangeLabel } from '@/components/metrics/ChangeLabel'; @@ -30,8 +30,20 @@ export const MetricCard = ({ }: MetricCardProps) => { const diff = value - change; const pct = diff !== 0 ? ((value - diff) / diff) * 100 : value !== 0 ? 100 : 0; - const props = useSpring({ x: Number(value) || 0, from: { x: 0 } }); - const changeProps = useSpring({ x: Number(pct) || 0, from: { x: 0 } }); + const x = Number(value) || 0; + const p = Number(pct) || 0; + const xSpring = useSpring(0, { stiffness: 170, damping: 26 }); + const pctSpring = useSpring(0, { stiffness: 170, damping: 26 }); + const valueText = useTransform(xSpring, n => formatValue(n)); + const pctText = useTransform(pctSpring, n => `${Math.abs(~~n)}%`); + + useEffect(() => { + xSpring.set(x); + }, [x, xSpring]); + + useEffect(() => { + pctSpring.set(p); + }, [p, pctSpring]); return ( )} - {props?.x?.to(x => formatValue(x))} + {valueText} {showChange && ( - {changeProps?.x?.to(x => `${Math.abs(~~x)}%`)} + {pctText} )} diff --git a/src/components/metrics/PerformanceCard.tsx b/src/components/metrics/PerformanceCard.tsx index 6a6345aaa..0851526d7 100644 --- a/src/components/metrics/PerformanceCard.tsx +++ b/src/components/metrics/PerformanceCard.tsx @@ -1,6 +1,6 @@ -import { config, useSpring } from '@react-spring/web'; import { Column, Text } from '@umami/react-zen'; -import { useRef } from 'react'; +import { useSpring, useTransform } from 'motion/react'; +import { useEffect, useRef } from 'react'; import { AnimatedDiv } from '@/components/common/AnimatedDiv'; import { Badge } from '@/components/common/Badge'; import { useMessages } from '@/components/hooks'; @@ -45,10 +45,14 @@ export const PerformanceCard = ({ const metricChanged = prevMetricRef.current !== metric; if (metricChanged) prevMetricRef.current = metric; - const spring = useSpring({ - value: !Number.isNaN(value) ? value : 0, - config: metricChanged ? { duration: 0 } : config.default, - }); + const target = !Number.isNaN(value) ? value : 0; + const spring = useSpring(target, { stiffness: 170, damping: 26 }); + const display = useTransform(spring, n => formatValue(n)); + + useEffect(() => { + if (metricChanged) spring.jump(target); + else spring.set(target); + }, [target, metricChanged, spring]); return ( - {spring.value.to(n => formatValue(n))} + {display} {t(labels[rating === 'needs-improvement' ? 'needsImprovement' : rating])} diff --git a/src/components/property-data/PropertyChart.tsx b/src/components/property-data/PropertyChart.tsx new file mode 100644 index 000000000..0700ff1a7 --- /dev/null +++ b/src/components/property-data/PropertyChart.tsx @@ -0,0 +1,188 @@ +'use client'; +import { Column, Grid } from '@umami/react-zen'; +import { colord } from 'colord'; +import { useCallback, useMemo } from 'react'; +import { BarChart } from '@/components/charts/BarChart'; +import { PieChart } from '@/components/charts/PieChart'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { + useDateRange, + useLocale, + useMessages, + usePropertyArraySeriesQuery, + usePropertySeriesQuery, + useTimezone, +} from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; +import { ListTable } from '@/components/metrics/ListTable'; +import { renderDateLabels } from '@/lib/charts'; +import { CHART_COLORS } from '@/lib/constants'; +import { generateTimeSeries } from '@/lib/date'; +import type { EventDataSeriesPoint, PropertyFilter } from '@/lib/types'; + +export function PropertyChart({ + source, + websiteId, + propertyName, + propertyFilters = [], + eventName, + seriesType = 'property', +}: { + source: PropertyDataSource; + websiteId: string; + propertyName: string; + propertyFilters?: PropertyFilter[]; + eventName?: string; + seriesType?: 'property' | 'array'; +}) { + const { t, labels } = useMessages(); + const { timezone } = useTimezone(); + const { dateRange: { startDate, endDate, unit } } = useDateRange({ timezone }); + const { locale, dateLocale } = useLocale(); + const propertySeriesQuery = usePropertySeriesQuery( + source, + websiteId, + propertyName, + propertyFilters, + eventName, + { enabled: seriesType === 'property' }, + ); + const arraySeriesQuery = usePropertyArraySeriesQuery( + source, + websiteId, + propertyName, + propertyFilters, + eventName, + { enabled: seriesType === 'array' }, + ); + const { data, isLoading, isFetching, error } = + seriesType === 'array' ? arraySeriesQuery : propertySeriesQuery; + + const aggregated = useMemo(() => { + if (!data) return []; + const totals = data.reduce((obj: Record, { x, y }) => { + obj[x] = (obj[x] ?? 0) + y; + return obj; + }, {}); + return Object.entries(totals) + .map(([value, total]) => ({ value, total: total as number })) + .sort((a, b) => b.total - a.total); + }, [data]); + + const valueLabels = useMemo(() => aggregated.map(({ value }) => value), [aggregated]); + const colorMap = useMemo( + () => + valueLabels.reduce( + (obj, label, index) => { + obj[label] = CHART_COLORS[index % CHART_COLORS.length]; + return obj; + }, + {} as Record, + ), + [valueLabels], + ); + + const chartData = useMemo(() => { + if (!data) return; + + const map = data.reduce((obj: Record, { x, t, y }) => { + if (!obj[x]) obj[x] = []; + obj[x].push({ x, t, y }); + return obj; + }, {}); + + if (!Object.keys(map).length) { + return { + datasets: [ + { + data: generateTimeSeries([], startDate, endDate, unit, dateLocale), + lineTension: 0, + borderWidth: 1, + }, + ], + }; + } + + const keys = [ + ...valueLabels.filter(label => map[label]), + ...Object.keys(map).filter(key => !valueLabels.includes(key)), + ]; + + return { + datasets: keys.map((key, index) => { + const color = colord(colorMap[key] || CHART_COLORS[index % CHART_COLORS.length]); + return { + label: key, + data: generateTimeSeries( + map[key].map(({ t, y }) => ({ x: t, y })), + startDate, + endDate, + unit, + dateLocale, + ), + lineTension: 0, + backgroundColor: color.alpha(0.6).toRgbString(), + borderColor: color.alpha(0.7).toRgbString(), + borderWidth: 1, + }; + }), + }; + }, [data, startDate, endDate, unit, dateLocale, valueLabels, colorMap]); + + const renderXLabel = useCallback(renderDateLabels(unit, locale), [unit, locale]); + const propertySum = useMemo( + () => aggregated.reduce((sum, { total }) => sum + total, 0), + [aggregated], + ); + const tableData = useMemo(() => { + if (!aggregated.length || propertySum === 0) return []; + return aggregated.map(({ value, total }) => ({ + label: value, + count: total, + percent: 100 * (total / propertySum), + })); + }, [aggregated, propertySum]); + const pieChartData = useMemo(() => { + if (!aggregated.length) return null; + return { + labels: valueLabels, + datasets: [ + { + data: aggregated.map(({ total }) => total), + backgroundColor: valueLabels.map(label => colorMap[label]), + borderWidth: 0, + }, + ], + }; + }, [aggregated, valueLabels, colorMap]); + + return ( + + + {chartData && ( + + )} + + + + + {pieChartData && } + + + + ); +} diff --git a/src/components/property-data/PropertyDateChart.tsx b/src/components/property-data/PropertyDateChart.tsx new file mode 100644 index 000000000..4eb83d6ea --- /dev/null +++ b/src/components/property-data/PropertyDateChart.tsx @@ -0,0 +1,300 @@ +'use client'; +import { Column, Grid, Text, useTheme } from '@umami/react-zen'; +import { + differenceInCalendarDays, + format, + formatDistance, + isValid, + startOfDay, + startOfMonth, + startOfWeek, + startOfYear, + type Locale, +} from 'date-fns'; +import { toZonedTime } from 'date-fns-tz'; +import { type ReactNode, useCallback, useMemo } from 'react'; +import { BarChart } from '@/components/charts/BarChart'; +import { PieChart } from '@/components/charts/PieChart'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { useLocale, useMessages, usePropertyDateSeriesQuery, useTimezone } from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; +import { ListTable } from '@/components/metrics/ListTable'; +import { MetricsBar } from '@/components/metrics/MetricsBar'; +import { renderDateLabels } from '@/lib/charts'; +import { getThemeColors } from '@/lib/colors'; +import { CHART_COLORS } from '@/lib/constants'; +import { formatDate, generateTimeSeries } from '@/lib/date'; +import type { EventDataDateSeriesPoint, PropertyFilter } from '@/lib/types'; + +type DateChartUnit = 'day' | 'week' | 'month' | 'year'; +type ParsedDateRow = EventDataDateSeriesPoint & { date: Date }; + +function parseDateValue(value: string) { + const normalized = value?.trim().replace(' ', 'T').replace(/Z$/, '').replace(/\.\d+$/, ''); + const [datePart = '', timePart = '00:00:00'] = normalized.split('T'); + const [year = 0, month = 1, day = 1] = datePart.split('-').map(Number); + const [hour = 0, minute = 0, second = 0] = timePart.split(':').map(Number); + const date = new Date(year, month - 1, day, hour, minute, second); + + return isValid(date) ? date : null; +} + +function InsightCard({ label, value, hint }: { label: string; value: string; hint?: ReactNode }) { + return ( + + {label} + {value} + {hint && {hint}} + + ); +} + +function getChartUnit(minDate: Date, maxDate: Date): DateChartUnit { + const spanDays = differenceInCalendarDays(maxDate, minDate); + if (spanDays <= 45) return 'day'; + if (spanDays <= 180) return 'week'; + if (spanDays <= 730) return 'month'; + return 'year'; +} + +function getBucketStart(date: Date, unit: DateChartUnit, dateLocale: Locale) { + switch (unit) { + case 'week': + return startOfWeek(date, { locale: dateLocale }); + case 'month': + return startOfMonth(date); + case 'year': + return startOfYear(date); + default: + return startOfDay(date); + } +} + +export function PropertyDateChart({ + source, + websiteId, + propertyName, + propertyFilters = [], + eventName, +}: { + source: PropertyDataSource; + websiteId: string; + propertyName: string; + propertyFilters?: PropertyFilter[]; + eventName?: string; +}) { + const { theme } = useTheme(); + const { t, labels } = useMessages(); + const { locale, dateLocale } = useLocale(); + const { timezone } = useTimezone(); + const { colors } = useMemo(() => getThemeColors(theme), [theme]); + const query = usePropertyDateSeriesQuery(source, websiteId, propertyName, propertyFilters, eventName); + + const rows = useMemo(() => query.data ?? [], [query.data]); + const total = useMemo(() => rows.reduce((sum, { y }) => sum + y, 0), [rows]); + const zonedNow = useMemo(() => toZonedTime(new Date(), timezone), [timezone]); + + const exactDateRows = useMemo( + () => + rows + .map(row => { + const date = parseDateValue(row.t); + return date ? { ...row, date } : null; + }) + .filter((row): row is ParsedDateRow => row !== null) + .sort((a, b) => a.date.getTime() - b.date.getTime()), + [rows], + ); + + const minPropertyDate = exactDateRows[0]?.date ?? null; + const maxPropertyDate = exactDateRows[exactDateRows.length - 1]?.date ?? null; + const chartUnit = useMemo( + () => (minPropertyDate && maxPropertyDate ? getChartUnit(minPropertyDate, maxPropertyDate) : 'day'), + [maxPropertyDate, minPropertyDate], + ); + + const chartRows = useMemo(() => { + if (!exactDateRows.length) return []; + const buckets = exactDateRows.reduce( + (obj, row) => { + const bucketStart = getBucketStart(row.date, chartUnit, dateLocale); + const bucketKey = format(bucketStart, "yyyy-MM-dd'T'HH:mm:ss"); + obj[bucketKey] = { + t: bucketKey, + y: (obj[bucketKey]?.y ?? 0) + row.y, + }; + return obj; + }, + {} as Record, + ); + return Object.values(buckets).sort( + (a, b) => (parseDateValue(a.t)?.getTime() ?? 0) - (parseDateValue(b.t)?.getTime() ?? 0), + ); + }, [chartUnit, dateLocale, exactDateRows]); + + const chartData: any = useMemo(() => { + if (!minPropertyDate || !maxPropertyDate) { + return { + datasets: [ + { + label: t(labels.count), + data: [], + barPercentage: 0.9, + categoryPercentage: 0.9, + ...colors.chart.visitors, + borderWidth: 1, + }, + ], + }; + } + + return { + datasets: [ + { + label: t(labels.count), + data: generateTimeSeries( + chartRows.map(({ t, y }) => ({ x: t, y })), + minPropertyDate, + maxPropertyDate, + chartUnit, + dateLocale, + ), + barPercentage: 0.9, + categoryPercentage: 0.9, + ...colors.chart.visitors, + borderWidth: 1, + }, + ], + }; + }, [chartRows, chartUnit, colors, dateLocale, labels.count, maxPropertyDate, minPropertyDate, t]); + + const renderXLabel = useCallback(renderDateLabels(chartUnit, locale), [chartUnit, locale]); + + const weekdayTableData = useMemo(() => { + if (!exactDateRows.length || total === 0) return []; + const weekStartsOn = dateLocale.options?.weekStartsOn ?? 0; + const weekdayOrder = Array.from({ length: 7 }, (_, index) => (weekStartsOn + index) % 7); + const weekdayTotals = exactDateRows.reduce( + (obj, { date, y }) => { + const day = date.getDay(); + obj[day] = (obj[day] ?? 0) + y; + return obj; + }, + {} as Record, + ); + + return weekdayOrder.map(day => { + const referenceDate = new Date(2026, 0, 4 + day); + const count = weekdayTotals[day] ?? 0; + + return { + label: format(referenceDate, 'EEEE', { locale: dateLocale }), + count, + percent: total ? 100 * (count / total) : 0, + }; + }); + }, [dateLocale, exactDateRows, total]); + + const topDateByDay = useMemo(() => { + if (!exactDateRows.length || total === 0) return null; + const dayTotals = exactDateRows.reduce( + (obj, { date, y }) => { + const dayDate = startOfDay(date); + const key = format(dayDate, 'yyyy-MM-dd'); + obj[key] = { date: dayDate, count: (obj[key]?.count ?? 0) + y }; + return obj; + }, + {} as Record, + ); + return Object.values(dayTotals).sort((a, b) => b.count - a.count || b.date.getTime() - a.date.getTime())[0]; + }, [exactDateRows, total]); + + const topWeekday = useMemo(() => [...weekdayTableData].sort((a, b) => b.count - a.count)[0], [weekdayTableData]); + const weekdayLabels = useMemo(() => weekdayTableData.map(({ label }) => label), [weekdayTableData]); + const weekdayColorMap = useMemo( + () => + weekdayLabels.reduce((obj, label, index) => { + obj[label] = CHART_COLORS[index % CHART_COLORS.length]; + return obj; + }, {} as Record), + [weekdayLabels], + ); + + const weekdayPieChartData = useMemo(() => { + if (!weekdayTableData.length) return null; + return { + labels: weekdayLabels, + datasets: [ + { + data: weekdayTableData.map(({ count }) => count), + backgroundColor: weekdayLabels.map(label => weekdayColorMap[label]), + borderWidth: 0, + }, + ], + }; + }, [weekdayColorMap, weekdayLabels, weekdayTableData]); + + return ( + + + + + + + + + + + {chartData && ( + + )} + + + + + {weekdayPieChartData && } + + + + ); +} diff --git a/src/components/property-data/PropertyFilterBar.tsx b/src/components/property-data/PropertyFilterBar.tsx new file mode 100644 index 000000000..4fa27eac3 --- /dev/null +++ b/src/components/property-data/PropertyFilterBar.tsx @@ -0,0 +1,129 @@ +'use client'; +import { Button, Icon, Row, Text, Tooltip, TooltipTrigger } from '@umami/react-zen'; +import { useMessages } from '@/components/hooks'; +import { X } from '@/components/icons'; +import { OPERATORS } from '@/lib/constants'; +import type { PropertyFilter } from '@/lib/types'; + +export function PropertyFilterBar({ + filters, + onChange, +}: { + filters: PropertyFilter[]; + onChange: (filters: PropertyFilter[]) => void; +}) { + const { t, labels } = useMessages(); + + if (!filters.length) return null; + + const operatorLabel = (op: string) => { + switch (op) { + case OPERATORS.equals: + return t(labels.is); + case OPERATORS.notEquals: + return t(labels.isNot); + case OPERATORS.contains: + return t(labels.contains); + case OPERATORS.doesNotContain: + return t(labels.doesNotContain); + case OPERATORS.regex: + return t(labels.regexMatch); + case OPERATORS.notRegex: + return t(labels.regexNotMatch); + case OPERATORS.greaterThan: + return t(labels.greaterThan); + case OPERATORS.lessThan: + return t(labels.lessThan); + case OPERATORS.greaterThanEquals: + return t(labels.greaterThanEquals); + case OPERATORS.lessThanEquals: + return t(labels.lessThanEquals); + case OPERATORS.before: + return t(labels.before); + case OPERATORS.after: + return t(labels.after); + default: + return op; + } + }; + + return ( + + + {filters.map((filter, index) => ( + onChange(filters.filter((_, i) => i !== index))} + /> + ))} + + + + + {t(labels.clearAll)} + + + + ); +} + +function FilterPill({ + label, + operator, + value, + onRemove, +}: { + label: string; + operator: string; + value: string; + onRemove: () => void; +}) { + return ( + + + + {label} + + {operator} + + {value} + + + + + + + ); +} diff --git a/src/components/property-data/PropertyFilterButton.tsx b/src/components/property-data/PropertyFilterButton.tsx new file mode 100644 index 000000000..b5beb3de6 --- /dev/null +++ b/src/components/property-data/PropertyFilterButton.tsx @@ -0,0 +1,41 @@ +'use client'; +import { useMessages } from '@/components/hooks'; +import { ListFilter } from '@/components/icons'; +import { DialogButton } from '@/components/input/DialogButton'; +import type { PropertyFilter } from '@/lib/types'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; +import { PropertyFilterEditForm } from './PropertyFilterEditForm'; + +export function PropertyFilterButton({ + source, + websiteId, + eventName, + fields, + filters, + onApply, +}: { + source: PropertyDataSource; + websiteId: string; + eventName?: string; + fields?: Array<{ propertyName: string; dataType: number }>; + filters: PropertyFilter[]; + onApply: (filters: PropertyFilter[]) => void; +}) { + const { t, labels } = useMessages(); + + return ( + } label={t(labels.propertyFilter)} variant="outline"> + {({ close }) => ( + + )} + + ); +} diff --git a/src/components/property-data/PropertyFilterEditForm.tsx b/src/components/property-data/PropertyFilterEditForm.tsx new file mode 100644 index 000000000..6f5e9bce6 --- /dev/null +++ b/src/components/property-data/PropertyFilterEditForm.tsx @@ -0,0 +1,135 @@ +'use client'; +import { Button, Column, Grid, Icon, List, ListItem, Menu, MenuItem, MenuTrigger, Popover, Row } from '@umami/react-zen'; +import { format } from 'date-fns'; +import { useState } from 'react'; +import { Empty } from '@/components/common/Empty'; +import { useMessages, useMobile, usePropertyFieldsQuery } from '@/components/hooks'; +import { Plus } from '@/components/icons'; +import { DATA_TYPE, OPERATORS } from '@/lib/constants'; +import type { PropertyFilter } from '@/lib/types'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; +import { PropertyFilterRecord } from './PropertyFilterRecord'; + +export function PropertyFilterEditForm({ + source, + websiteId, + eventName, + fields: providedFields, + value, + onApply, + onClose, +}: { + source: PropertyDataSource; + websiteId: string; + eventName?: string; + fields?: Array<{ propertyName: string; dataType: number }>; + value: PropertyFilter[]; + onApply: (filters: PropertyFilter[]) => void; + onClose: () => void; +}) { + const { t, labels, messages } = useMessages(); + const { isMobile } = useMobile(); + const [filters, setFilters] = useState(value); + const { data: queriedFields = [] } = usePropertyFieldsQuery(source, websiteId, eventName, { + enabled: !providedFields, + }); + const fields = providedFields ?? queriedFields; + + const handleAdd = (propertyName: string) => { + const field = (fields as any[]).find(f => f.propertyName === propertyName); + const dataType: number = field?.dataType ?? DATA_TYPE.string; + setFilters(prev => [ + ...prev, + { + propertyName, + dataType, + operator: + dataType === DATA_TYPE.date + ? OPERATORS.before + : dataType === DATA_TYPE.array + ? OPERATORS.contains + : OPERATORS.equals, + value: + dataType === DATA_TYPE.boolean + ? 'true' + : dataType === DATA_TYPE.date + ? format(new Date(), 'yyyy-MM-dd') + : '', + }, + ]); + }; + + return ( + + + + + + + + handleAdd(key.toString())} + style={{ maxHeight: 'calc(100vh - 2rem)', overflowY: 'auto' }} + > + {(fields as any[]).map(field => ( + + {field.propertyName} + + ))} + + + + + + handleAdd(key.toString())}> + {(fields as any[]).map(field => ( + + {field.propertyName} + + ))} + + + + {filters.map((filter, index) => ( + setFilters(prev => prev.map((item, i) => (i === index ? f : item)))} + onRemove={() => setFilters(prev => prev.filter((_, i) => i !== index))} + /> + ))} + {!filters.length && } + + + + + + + + + + + + ); +} diff --git a/src/components/property-data/PropertyFilterRecord.tsx b/src/components/property-data/PropertyFilterRecord.tsx new file mode 100644 index 000000000..9a36df9f4 --- /dev/null +++ b/src/components/property-data/PropertyFilterRecord.tsx @@ -0,0 +1,274 @@ +'use client'; +import { Button, Calendar, Column, ComboBox, Dialog, DialogTrigger, Grid, Icon, Label, ListItem, Loading, Popover, Row, Select, TextField } from '@umami/react-zen'; +import { format, parseISO } from 'date-fns'; +import { useState } from 'react'; +import { DateDisplay } from '@/components/common/DateDisplay'; +import { Empty } from '@/components/common/Empty'; +import { MultiSelect } from '@/components/common/MultiSelect'; +import { useMessages, usePropertyValuesQuery } from '@/components/hooks'; +import { X } from '@/components/icons'; +import { DATA_TYPE, OPERATORS } from '@/lib/constants'; +import { getMaxSelectableDate } from '@/lib/date'; +import type { Operator, PropertyFilter } from '@/lib/types'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; + +const STRING_OPERATORS: Operator[] = [ + OPERATORS.equals, + OPERATORS.notEquals, + OPERATORS.contains, + OPERATORS.doesNotContain, + OPERATORS.regex, + OPERATORS.notRegex, +]; +const NUMERIC_OPERATORS: Operator[] = [ + OPERATORS.equals, + OPERATORS.notEquals, + OPERATORS.greaterThan, + OPERATORS.lessThan, + OPERATORS.greaterThanEquals, + OPERATORS.lessThanEquals, +]; +const BOOLEAN_OPERATORS: Operator[] = [OPERATORS.equals, OPERATORS.notEquals]; +const DATE_OPERATORS: Operator[] = [OPERATORS.before, OPERATORS.after]; +const ARRAY_OPERATORS: Operator[] = [OPERATORS.contains, OPERATORS.doesNotContain]; +const MULTI_OPERATORS: Operator[] = [OPERATORS.equals, OPERATORS.notEquals]; +const FREE_TEXT_OPERATORS: Operator[] = [ + OPERATORS.contains, + OPERATORS.doesNotContain, + OPERATORS.regex, + OPERATORS.notRegex, +]; + +export function PropertyFilterRecord({ + source, + websiteId, + eventName, + filter, + filters, + onChange, + onRemove, +}: { + source: PropertyDataSource; + websiteId: string; + eventName?: string; + filter: PropertyFilter; + filters: PropertyFilter[]; + onChange: (filter: PropertyFilter) => void; + onRemove: () => void; +}) { + const { t, labels, messages } = useMessages(); + const [search, setSearch] = useState(''); + + const isNumeric = filter.dataType === DATA_TYPE.number; + const isBoolean = filter.dataType === DATA_TYPE.boolean; + const isDate = filter.dataType === DATA_TYPE.date; + const isArray = filter.dataType === DATA_TYPE.array; + const operators = isNumeric + ? NUMERIC_OPERATORS + : isBoolean + ? BOOLEAN_OPERATORS + : isDate + ? DATE_OPERATORS + : isArray + ? ARRAY_OPERATORS + : STRING_OPERATORS; + const isFreeText = !isArray && FREE_TEXT_OPERATORS.includes(filter.operator); + + const { data, isLoading } = usePropertyValuesQuery( + source, + websiteId, + filter.propertyName, + filter.dataType, + filters.filter(f => f !== filter), + eventName, + { enabled: !isNumeric && !isBoolean && !isDate && !isFreeText }, + ); + + const values = (data as Array<{ value: string }> | undefined)?.map(d => d.value) ?? []; + const filteredValues = search + ? values.filter(v => v.toLowerCase().includes(search.toLowerCase())) + : values; + const selected = filter.value ? filter.value.split(',').filter(Boolean) : []; + + const operatorLabel = (op: Operator) => { + switch (op) { + case OPERATORS.equals: return t(labels.is); + case OPERATORS.notEquals: return t(labels.isNot); + case OPERATORS.contains: return t(labels.contains); + case OPERATORS.doesNotContain: return t(labels.doesNotContain); + case OPERATORS.regex: return t(labels.regexMatch); + case OPERATORS.notRegex: return t(labels.regexNotMatch); + case OPERATORS.greaterThan: return t(labels.greaterThan); + case OPERATORS.lessThan: return t(labels.lessThan); + case OPERATORS.greaterThanEquals: return t(labels.greaterThanEquals); + case OPERATORS.lessThanEquals: return t(labels.lessThanEquals); + case OPERATORS.before: return t(labels.before); + case OPERATORS.after: return t(labels.after); + default: return op; + } + }; + + const handleOperatorChange = (op: Operator) => { + const wasMulti = MULTI_OPERATORS.includes(filter.operator); + const isMulti = MULTI_OPERATORS.includes(op); + onChange({ + ...filter, + operator: op, + value: wasMulti === isMulti ? filter.value : '', + }); + }; + + return ( + + + + + + {isBoolean ? ( + + ) : isDate ? ( + onChange({ ...filter, value })} + /> + ) : isArray ? ( + { + setSearch(v); + onChange({ ...filter, value: v }); + }} + formValue="text" + allowsEmptyCollection + allowsCustomValue + renderEmptyState={() => + isLoading ? ( + + ) : ( + + ) + } + > + {filteredValues.map(v => ( + + {v} + + ))} + + ) : isNumeric || isFreeText ? ( + onChange({ ...filter, value: v })} + inputMode={isNumeric ? 'numeric' : 'text'} + /> + ) : ( + onChange({ ...filter, value: vals.join(',') })} + searchValue={search} + onSearch={setSearch} + allowSearch + renderValue={vals => (vals.length > 0 ? vals.join(', ') : undefined)} + renderEmptyState={() => + isLoading ? ( + + ) : ( + + ) + } + > + {filteredValues.map(v => ( + + {v} + + ))} + + )} + + + + + + + ); +} + +function DateValuePicker({ + value, + onChange, +}: { + value: string; + onChange: (value: string) => void; +}) { + const { t, labels } = useMessages(); + const [showPicker, setShowPicker] = useState(false); + const selectedDate = getSelectedDate(value); + const [draftDate, setDraftDate] = useState(selectedDate); + + return ( + + + + + + + + + + + + + + + ); +} + +function getSelectedDate(value?: string) { + if (!value) { + return new Date(); + } + + const date = parseISO(value); + + return Number.isNaN(date.getTime()) ? new Date() : date; +} diff --git a/src/components/property-data/PropertyNumericChart.tsx b/src/components/property-data/PropertyNumericChart.tsx new file mode 100644 index 000000000..ed98e23df --- /dev/null +++ b/src/components/property-data/PropertyNumericChart.tsx @@ -0,0 +1,137 @@ +'use client'; +import { Column, useTheme } from '@umami/react-zen'; +import { useCallback, useMemo } from 'react'; +import { BarChart } from '@/components/charts/BarChart'; +import { LoadingPanel } from '@/components/common/LoadingPanel'; +import { + useDateRange, + useLocale, + useMessages, + usePropertyNumericSeriesQuery, + usePropertyNumericStatsQuery, + useTimezone, +} from '@/components/hooks'; +import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; +import { MetricCard } from '@/components/metrics/MetricCard'; +import { MetricsBar } from '@/components/metrics/MetricsBar'; +import { renderDateLabels } from '@/lib/charts'; +import { getThemeColors } from '@/lib/colors'; +import { generateTimeSeries } from '@/lib/date'; +import { formatLongNumber } from '@/lib/format'; +import type { PropertyFilter } from '@/lib/types'; + +export function PropertyNumericChart({ + source, + websiteId, + propertyName, + propertyFilters = [], + eventName, +}: { + source: PropertyDataSource; + websiteId: string; + propertyName: string; + propertyFilters?: PropertyFilter[]; + eventName?: string; +}) { + const { t, labels } = useMessages(); + const { theme } = useTheme(); + const { timezone } = useTimezone(); + const { dateRange: { startDate, endDate, unit } } = useDateRange({ timezone }); + const { locale, dateLocale } = useLocale(); + const { colors } = useMemo(() => getThemeColors(theme), [theme]); + + const sumQuery = usePropertyNumericSeriesQuery(source, websiteId, propertyName, 'sum', propertyFilters, eventName); + const avgQuery = usePropertyNumericSeriesQuery(source, websiteId, propertyName, 'avg', propertyFilters, eventName); + const statsQuery = usePropertyNumericStatsQuery(source, websiteId, propertyName, propertyFilters, eventName); + + const sumRows = useMemo(() => (sumQuery.data as { t: string; y: number }[] | undefined) ?? [], [sumQuery.data]); + const avgRows = useMemo(() => (avgQuery.data as { t: string; y: number }[] | undefined) ?? [], [avgQuery.data]); + const stats = statsQuery.data; + + const formatMetricValue = useCallback( + (n: number) => + Number(n).toLocaleString(locale, { + maximumFractionDigits: 2, + minimumFractionDigits: Number.isInteger(Number(n)) ? 0 : 2, + }), + [locale], + ); + + const chartData: any = useMemo(() => { + if (!sumQuery.data && !avgQuery.data) return; + + return { + datasets: [ + { + type: 'bar', + label: t(labels.sum), + data: generateTimeSeries( + sumRows.map(({ t, y }) => ({ x: t, y })), + startDate, + endDate, + unit, + dateLocale, + ), + barPercentage: 0.9, + categoryPercentage: 0.9, + ...colors.chart.visitors, + borderWidth: 1, + }, + { + type: 'bar', + label: t(labels.average), + data: generateTimeSeries( + avgRows.map(({ t, y }) => ({ x: t, y })), + startDate, + endDate, + unit, + dateLocale, + ), + barPercentage: 0.9, + categoryPercentage: 0.9, + ...colors.chart.views, + borderWidth: 1, + }, + ], + }; + }, [avgQuery.data, avgRows, colors, dateLocale, endDate, labels.average, labels.sum, startDate, sumQuery.data, sumRows, t, unit]); + + const renderXLabel = useCallback(renderDateLabels(unit, locale), [unit, locale]); + + return ( + + + + + + + + + + + + {chartData && ( + + )} + + + ); +} diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index 0a8739b6c..b6fb4f874 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -1,14 +1,14 @@ +import { CLICKHOUSE } from '@/lib/db'; import { type ClickHouseClient, createClient } from '@clickhouse/client'; import { formatInTimeZone } from 'date-fns-tz'; import debug from 'debug'; -import { CLICKHOUSE } from '@/lib/db'; -import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from './constants'; +import { DATA_TYPE, DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from './constants'; import { filtersObjectToArray } from './params'; -import type { QueryFilters, QueryOptions } from './types'; +import type { Operator, PropertyFilter, QueryFilters, QueryOptions } from './types'; export const CLICKHOUSE_DATE_FORMATS = { utc: '%Y-%m-%dT%H:%i:%SZ', - second: '%Y-%m-%d %H:%i:%S', + second: '%Y-%m-%dT%H:%i:%S', minute: '%Y-%m-%d %H:%i:00', hour: '%Y-%m-%d %H:00:00', day: '%Y-%m-%d', @@ -18,10 +18,19 @@ export const CLICKHOUSE_DATE_FORMATS = { const log = debug('umami:clickhouse'); +const EQUALITY_OPERATORS: Operator[] = [OPERATORS.equals, OPERATORS.notEquals]; +const REGEX_OPERATORS: Operator[] = [OPERATORS.regex, OPERATORS.notRegex]; + let clickhouse: ClickHouseClient; const enabled = Boolean(process.env.CLICKHOUSE_URL); function getClient() { + const clickhouseUrl = process.env.CLICKHOUSE_URL; + + if (!clickhouseUrl) { + throw new Error('CLICKHOUSE_URL is not set.'); + } + const { hostname, port, @@ -29,7 +38,7 @@ function getClient() { protocol, username = 'default', password, - } = new URL(process.env.CLICKHOUSE_URL); + } = new URL(clickhouseUrl); const client = createClient({ url: `${protocol}//${hostname}:${port}`, @@ -70,13 +79,7 @@ function getSearchSQL(column: string, param: string = 'search'): string { return `and positionCaseInsensitive(${column}, {${param}:String}) > 0`; } -function mapFilter( - column: string, - operator: string, - name: string, - type: string = 'String', - paramName?: string, -) { +function mapFilter(column: string, operator: Operator, name: string, type: string = 'String', paramName?: string) { const param = paramName ?? name; const value = `{${param}:${type}}`; @@ -210,7 +213,7 @@ function getQueryParams(filters: Record) { const key = paramName ?? name; - obj[key] = ([OPERATORS.equals, OPERATORS.notEquals] as string[]).includes(operator) + obj[key] = EQUALITY_OPERATORS.includes(operator) ? Array.isArray(value) ? value : [value] @@ -235,6 +238,115 @@ function parseFilters(filters: Record, options?: QueryOptions) { }; } +function getPropertyFilterQuery( + filters: PropertyFilter[] = [], + propertyType: 'event' | 'session' = 'event', + timezone?: string, +): { + sql: string; + params: Record; +} { + if (!filters.length) return { sql: '', params: {} }; + + const parts: string[] = []; + const params: Record = {}; + const table = propertyType === 'event' ? 'event_data' : 'session_data final'; + const column = propertyType === 'event' ? 'event_id' : 'session_id'; + const outerColumn = propertyType === 'event' ? 'event_id' : 'website_event.session_id'; + + filters.forEach(({ propertyName, dataType, operator, value }, i) => { + const keyParam = `pf_key_${i}`; + const valParam = `pf_val_${i}`; + params[keyParam] = propertyName; + + let condition: string; + switch (dataType) { + case DATA_TYPE.number: { + const col = 'number_value'; + params[valParam] = parseFloat(value) || 0; + const opMap: Record = { + [OPERATORS.equals]: `${col} = {${valParam}:Float64}`, + [OPERATORS.notEquals]: `${col} != {${valParam}:Float64}`, + [OPERATORS.greaterThan]: `${col} > {${valParam}:Float64}`, + [OPERATORS.lessThan]: `${col} < {${valParam}:Float64}`, + [OPERATORS.greaterThanEquals]: `${col} >= {${valParam}:Float64}`, + [OPERATORS.lessThanEquals]: `${col} <= {${valParam}:Float64}`, + }; + condition = opMap[operator] ?? `${col} = {${valParam}:Float64}`; + break; + } + case DATA_TYPE.date: { + if (!value) return; + params[valParam] = value; + const dateCol = timezone + ? `toDate(toTimezone(date_value, {timezone:String}))` + : `toDate(toTimezone(date_value, 'UTC'))`; + const opMap: Record = { + [OPERATORS.before]: `${dateCol} < {${valParam}:Date}`, + [OPERATORS.after]: `${dateCol} > {${valParam}:Date}`, + }; + condition = opMap[operator] ?? `${dateCol} = {${valParam}:Date}`; + break; + } + case DATA_TYPE.array: { + if (!value) return; + params[valParam] = value; + condition = + operator === OPERATORS.contains + ? `has(JSONExtract(ifNull(string_value, '[]'), 'Array(String)'), {${valParam}:String})` + : `not has(JSONExtract(ifNull(string_value, '[]'), 'Array(String)'), {${valParam}:String})`; + break; + } + default: { + const col = 'string_value'; + + if (EQUALITY_OPERATORS.includes(operator)) { + const vals = value.split(',').filter(Boolean); + if (!vals.length) return; + params[valParam] = vals; + condition = mapFilter( + col, + operator === OPERATORS.equals ? OPERATORS.equals : OPERATORS.notEquals, + valParam, + 'String', + ); + } else if (REGEX_OPERATORS.includes(operator)) { + if (!value) return; + params[valParam] = value; + condition = mapFilter( + col, + operator === OPERATORS.regex ? OPERATORS.regex : OPERATORS.notRegex, + valParam, + 'String', + ); + } else { + if (!value) return; + params[valParam] = value; + condition = mapFilter( + col, + operator === OPERATORS.contains ? OPERATORS.contains : OPERATORS.doesNotContain, + valParam, + 'String', + ); + } + break; + } + } + + parts.push(`and ${outerColumn} in ( + select ${column} + from ${table} + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and data_key = {${keyParam}:String} + and data_type = ${dataType} + and ${condition} + )`); + }); + + return { sql: parts.join('\n'), params }; +} + async function pagedRawQuery( query: string, queryParams: Record, @@ -306,7 +418,7 @@ async function findFirst(data: any[]) { async function connect() { if (enabled && !clickhouse) { - clickhouse = process.env.CLICKHOUSE_URL && (globalThis[CLICKHOUSE] || getClient()); + clickhouse = globalThis[CLICKHOUSE] || getClient(); } return clickhouse; @@ -321,6 +433,7 @@ export default { getDateSQL, getSearchSQL, getFilterQuery, + getPropertyFilterQuery, getUTCString, parseFilters, pagedRawQuery, diff --git a/src/lib/date.ts b/src/lib/date.ts index 91af88f67..82fba23f8 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -38,7 +38,7 @@ import { subWeeks, subYears, } from 'date-fns'; -import { utcToZonedTime } from 'date-fns-tz'; +import { toZonedTime } from 'date-fns-tz'; import { getDateLocale } from '@/lib/lang'; import type { DateRange } from '@/lib/types'; @@ -113,6 +113,10 @@ export function normalizeTimezone(timezone: string): string { return TIMEZONE_MAPPINGS[timezone] || timezone; } +export function getMaxSelectableDate(now = new Date()) { + return max([endOfYear(now), addMonths(now, 6)]); +} + export function isValidTimezone(timezone: string) { try { const normalizedTimezone = normalizeTimezone(timezone); @@ -164,7 +168,7 @@ export function parseDateRange( } const date = new Date(); - const now = timezone ? utcToZonedTime(date, timezone) : date; + const now = timezone ? toZonedTime(date, timezone) : date; const dateLocale = getDateLocale(locale); const { num = 1, unit } = parseDateValue(value); diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 2e78a1f35..643ed01a2 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -77,8 +77,10 @@ function decodeHeader(s: string | undefined | null): string | undefined | null { } export async function getLocation(ip: string = '', headers: Headers, skipHeaders: boolean) { - // Ignore local ips - if (!ip || (await isLocalhost(ip))) { + const cleanIp = stripPort(ip); + + // Ignore local or invalid ips + if (!cleanIp || !ipaddr.isValid(cleanIp) || (await isLocalhost(cleanIp))) { return null; } @@ -108,7 +110,7 @@ export async function getLocation(ip: string = '', headers: Headers, skipHeaders ); } - const result = globalThis[MAXMIND]?.get(stripPort(ip)); + const result = globalThis[MAXMIND]?.get(cleanIp); if (result) { const country = result.country?.iso_code ?? result?.registered_country?.iso_code; diff --git a/src/lib/generate.ts b/src/lib/generate.ts index 8e25aa091..752c0b609 100644 --- a/src/lib/generate.ts +++ b/src/lib/generate.ts @@ -1,10 +1,11 @@ -import prand from 'pure-rand'; +import { uniformInt } from 'pure-rand/distribution/uniformInt'; +import { xoroshiro128plus } from 'pure-rand/generator/xoroshiro128plus'; const seed = Date.now() ^ (Math.random() * 0x100000000); -const rng = prand.xoroshiro128plus(seed); +const rng = xoroshiro128plus(seed); export function random(min: number, max: number) { - return prand.unsafeUniformIntDistribution(min, max, rng); + return uniformInt(rng, min, max); } export function getRandomChars( diff --git a/src/lib/ip.ts b/src/lib/ip.ts index a78c7e56e..08e77c65e 100644 --- a/src/lib/ip.ts +++ b/src/lib/ip.ts @@ -84,9 +84,7 @@ export function getIpAddress(headers: Headers) { if (header === 'forwarded') { const match = ip.match(/for=(\[?[0-9a-fA-F:.]+]?)/); - if (match) { - return resolveIp(match[1]); - } + return match ? resolveIp(match[1]) : undefined; } return resolveIp(ip); diff --git a/src/lib/params.ts b/src/lib/params.ts index f1452254d..50cb6db2d 100644 --- a/src/lib/params.ts +++ b/src/lib/params.ts @@ -1,5 +1,16 @@ -import { FILTER_COLUMNS, OPERATORS } from '@/lib/constants'; -import type { Filter, QueryFilters, QueryOptions } from '@/lib/types'; +import { DATA_TYPE, FILTER_COLUMNS, OPERATORS } from '@/lib/constants'; +import type { Filter, Operator, PropertyFilter, QueryFilters, QueryOptions } from '@/lib/types'; + +const VALID_OPERATORS: Operator[] = Object.values(OPERATORS); +const VALID_EVENT_DATA_TYPES = Object.values(DATA_TYPE); + +function resolveOperator(value?: string): Operator | undefined { + if (!value) { + return undefined; + } + + return VALID_OPERATORS.find(operator => operator === value); +} export function parseFilterValue(param: any) { if (typeof param === 'string') { @@ -9,7 +20,7 @@ export function parseFilterValue(param: any) { const [, operator, value] = param.match(regex) || []; - const resolvedOperator = operator || OPERATORS.equals; + const resolvedOperator = resolveOperator(operator) ?? OPERATORS.equals; const resolvedValue = value ?? param; if (resolvedOperator === OPERATORS.equals || resolvedOperator === OPERATORS.notEquals) { @@ -88,3 +99,71 @@ export function filtersArrayToObject(filters: Filter[]) { return obj; }, {}); } + +function getPropertyFilterPrefix(key: string, prefixes: string[]) { + return prefixes.find(prefix => key.startsWith(`${prefix}_`)); +} + +export function parsePropertyFilters( + query: Record, + prefixes: string[] = ['pf'], +): PropertyFilter[] { + return Object.entries(query) + .flatMap(([key, val]) => { + const prefix = getPropertyFilterPrefix(key, prefixes); + + if (!prefix) { + return []; + } + + const stringValue = String(val); + const withoutPrefix = key.slice(prefix.length + 1); + const propertyName = withoutPrefix.replace(/\d+$/, ''); // strip trailing index digits + const prefixedDotMatch = stringValue.match(/^(\d+)\.([^.]+)\.(.*)$/); + const untypedDotMatch = stringValue.match(/^([^.]+)\.(.*)$/); + const explicitDataType = prefixedDotMatch ? Number(prefixedDotMatch[1]) : undefined; + const rawOperator = prefixedDotMatch ? prefixedDotMatch[2] : untypedDotMatch?.[1]; + const operator = resolveOperator(rawOperator); + + if (!operator || (explicitDataType !== undefined && !VALID_EVENT_DATA_TYPES.includes(explicitDataType))) { + return []; + } + + const value = prefixedDotMatch ? prefixedDotMatch[3] : untypedDotMatch?.[2]; + + if (value === undefined) { + return []; + } + + return [ + { + propertyName, + dataType: explicitDataType ?? DATA_TYPE.string, + operator, + value, + }, + ]; + }); +} + +export function parseEventPropertyFilters(query: Record) { + return parsePropertyFilters(query, ['pf']); +} + +export function serializePropertyFilters( + filters: PropertyFilter[], + prefix = 'pf', +): Record { + const counts: Record = {}; + return Object.fromEntries( + filters.map(f => { + const n = counts[f.propertyName] ?? 0; + counts[f.propertyName] = n + 1; + return [`${prefix}_${f.propertyName}${n > 0 ? n : ''}`, `${f.dataType}.${f.operator}.${f.value}`]; + }), + ); +} + +export function serializeEventPropertyFilters(filters: PropertyFilter[]) { + return serializePropertyFilters(filters, 'pf'); +} diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index c3b6aaca3..1da0f81b7 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -1,13 +1,17 @@ +import { PrismaClient } from '@/generated/prisma/client'; import { PrismaPg } from '@prisma/adapter-pg'; import { readReplicas } from '@prisma/extension-read-replicas'; import debug from 'debug'; -import { PrismaClient } from '@/generated/prisma/client'; -import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS, SESSION_COLUMNS } from './constants'; +import { DATA_TYPE, DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS, SESSION_COLUMNS } from './constants'; import { filtersObjectToArray } from './params'; -import type { Operator, QueryFilters, QueryOptions } from './types'; +import type { Operator, PropertyFilter, QueryFilters, QueryOptions } from './types'; const log = debug('umami:prisma'); +const EQUALITY_OPERATORS: Operator[] = [OPERATORS.equals, OPERATORS.notEquals]; +const SEARCH_OPERATORS: Operator[] = [OPERATORS.contains, OPERATORS.doesNotContain]; +const REGEX_OPERATORS: Operator[] = [OPERATORS.regex, OPERATORS.notRegex]; + const PRISMA = 'prisma'; const PRISMA_LOG_OPTIONS = { @@ -35,6 +39,15 @@ const DATE_FORMATS_UTC = { year: 'YYYY-01-01"T"HH24:00:00"Z"', }; +const DATE_STRING_FORMATS = { + utc: 'YYYY-MM-DD"T"HH24:MI:SS"Z"', + second: 'YYYY-MM-DD"T"HH24:MI:SS', +}; + +function isUtcTimezone(timezone?: string) { + return timezone?.toLowerCase() === 'utc'; +} + function getAddIntervalQuery(field: string, interval: string): string { return `${field} + interval '${interval}'`; } @@ -48,13 +61,21 @@ function getCastColumnQuery(field: string, type: string): string { } function getDateSQL(field: string, unit: string, timezone?: string): string { - if (timezone && timezone !== 'utc') { + if (timezone && !isUtcTimezone(timezone)) { return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${DATE_FORMATS[unit]}')`; } return `to_char(date_trunc('${unit}', ${field}), '${DATE_FORMATS_UTC[unit]}')`; } +function getDateStringSQL(field: string, unit: keyof typeof DATE_STRING_FORMATS = 'utc', timezone?: string): string { + if (timezone && !isUtcTimezone(timezone)) { + return `to_char(${field} at time zone '${timezone}', '${DATE_STRING_FORMATS[unit]}')`; + } + + return `to_char(${field}, '${DATE_STRING_FORMATS.utc}')`; +} + function getDateWeeklySQL(field: string, timezone?: string) { return `concat(extract(dow from (${field} at time zone '${timezone}')), ':', to_char((${field} at time zone '${timezone}'), 'HH24'))`; } @@ -216,9 +237,9 @@ function getQueryParams(filters: Record) { const key = paramName ?? name; - if (([OPERATORS.contains, OPERATORS.doesNotContain] as Operator[]).includes(operator)) { + if (SEARCH_OPERATORS.includes(operator)) { obj[key] = `%${value}%`; - } else if (([OPERATORS.equals, OPERATORS.notEquals] as Operator[]).includes(operator)) { + } else if (EQUALITY_OPERATORS.includes(operator)) { obj[key] = Array.isArray(value) ? value : [value]; } else { obj[key] = value; @@ -252,6 +273,119 @@ function parseFilters(filters: Record, options?: QueryOptions) { }; } +function getPropertyFilterQuery( + filters: PropertyFilter[] = [], + propertyType: 'event' | 'session' = 'event', + timezone?: string, +): { + sql: string; + params: Record; +} { + if (!filters.length) return { sql: '', params: {} }; + + const parts: string[] = []; + const params: Record = {}; + const table = propertyType === 'event' ? 'event_data' : 'session_data'; + const column = propertyType === 'event' ? 'website_event_id' : 'session_id'; + const outerColumn = + propertyType === 'event' ? 'website_event.event_id' : 'website_event.session_id'; + + filters.forEach(({ propertyName, dataType, operator, value }, i) => { + const keyParam = `pf_key_${i}`; + const valParam = `pf_val_${i}`; + params[keyParam] = propertyName; + + let condition: string; + switch (dataType) { + case DATA_TYPE.number: { + const col = 'cast(number_value as decimal)'; + params[valParam] = parseFloat(value) || 0; + const opMap: Record = { + [OPERATORS.equals]: `${col} = {{${valParam}}}`, + [OPERATORS.notEquals]: `${col} != {{${valParam}}}`, + [OPERATORS.greaterThan]: `${col} > {{${valParam}}}`, + [OPERATORS.lessThan]: `${col} < {{${valParam}}}`, + [OPERATORS.greaterThanEquals]: `${col} >= {{${valParam}}}`, + [OPERATORS.lessThanEquals]: `${col} <= {{${valParam}}}`, + }; + condition = opMap[operator] ?? `${col} = {{${valParam}}}`; + break; + } + case DATA_TYPE.date: { + if (!value) return; + params[valParam] = value; + const dateCol = + timezone && !isUtcTimezone(timezone) + ? `(date_value at time zone {{timezone}})::date` + : `(date_value at time zone 'utc')::date`; + const opMap: Record = { + [OPERATORS.before]: `${dateCol} < {{${valParam}::date}}`, + [OPERATORS.after]: `${dateCol} > {{${valParam}::date}}`, + }; + condition = opMap[operator] ?? `${dateCol} = {{${valParam}::date}}`; + break; + } + case DATA_TYPE.array: { + if (!value) return; + params[valParam] = value; + condition = + operator === OPERATORS.contains + ? `exists ( + select 1 + from jsonb_array_elements_text(coalesce(string_value, '[]')::jsonb) as array_item(value) + where array_item.value = {{${valParam}}} + )` + : `not exists ( + select 1 + from jsonb_array_elements_text(coalesce(string_value, '[]')::jsonb) as array_item(value) + where array_item.value = {{${valParam}}} + )`; + break; + } + default: { + const col = 'string_value'; + + if (EQUALITY_OPERATORS.includes(operator)) { + const vals = value.split(',').filter(Boolean); + if (!vals.length) return; + params[valParam] = vals; + condition = + operator === OPERATORS.equals + ? `${col} = ANY({{${valParam}}})` + : `${col} != ALL({{${valParam}}})`; + } else if (REGEX_OPERATORS.includes(operator)) { + if (!value) return; + params[valParam] = value; + condition = + operator === OPERATORS.regex + ? `${col} ~* {{${valParam}}}` + : `${col} !~* {{${valParam}}}`; + } else { + if (!value) return; + params[valParam] = `%${value}%`; + condition = + operator === OPERATORS.contains + ? `${col} ilike {{${valParam}}}` + : `${col} not ilike {{${valParam}}}`; + } + break; + } + } + + parts.push(`and ${outerColumn} in ( + select ${column} + from ${table} + where website_id = {{websiteId::uuid}} + and created_at between {{startDate}} and {{endDate}} + and data_key = {{${keyParam}}} + and data_type = ${dataType} + and ${condition} + )`); + }); + + return { sql: parts.join('\n'), params }; +} + async function rawQuery(sql: string, data: Record, name?: string): Promise { if (process.env.LOG_QUERY) { log('QUERY:\n', sql); @@ -362,7 +496,13 @@ function transaction(input: any, options?: any) { } function getSchema() { - const connectionUrl = new URL(process.env.DATABASE_URL); + const databaseUrl = process.env.DATABASE_URL; + + if (!databaseUrl) { + throw new Error('DATABASE_URL is not set.'); + } + + const connectionUrl = new URL(databaseUrl); return connectionUrl.searchParams.get('schema'); } @@ -371,6 +511,11 @@ function getClient() { const url = process.env.DATABASE_URL; const replicaUrl = process.env.DATABASE_REPLICA_URL; const logQuery = process.env.LOG_QUERY; + + if (!url) { + throw new Error('DATABASE_URL is not set.'); + } + const schema = getSchema(); const baseAdapter = new PrismaPg({ connectionString: url }, { schema }); @@ -424,8 +569,10 @@ export default { getCastColumnQuery, getDayDiffQuery, getDateSQL, + getDateStringSQL, getDateWeeklySQL, getFilterQuery, + getPropertyFilterQuery, getSearchParameters, getTimestampDiffSQL, getSearchSQL, diff --git a/src/lib/request.ts b/src/lib/request.ts index 69f6eb1d7..9b32b6736 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -1,5 +1,3 @@ -import { startOfMonth, subMonths } from 'date-fns'; -import { z } from 'zod'; import { checkAuth } from '@/lib/auth'; import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from '@/lib/constants'; import { getAllowedUnits, getMinimumUnit, maxDate, parseDateRange } from '@/lib/date'; @@ -8,6 +6,8 @@ import { filtersArrayToObject } from '@/lib/params'; import { badRequest, unauthorized } from '@/lib/response'; import type { QueryFilters } from '@/lib/types'; import { getWebsiteSegment } from '@/queries/prisma'; +import { startOfMonth, subMonths } from 'date-fns'; +import { z } from 'zod'; export async function parseRequest( request: Request, @@ -30,9 +30,9 @@ export async function parseRequest( } else if (isGet) { query = result.data; - // Re-add suffixed filter params (e.g., browser1, os2) stripped by Zod schema + // Re-add dynamic params stripped by Zod schema: suffixed filter params (browser1, os2) for (const key of Object.keys(rawQuery)) { - if (/\d+$/.test(key) && !(key in query)) { + if ((/\d+$/.test(key) || /^pf_/.test(key)) && !(key in query)) { query[key] = rawQuery[key]; } } diff --git a/src/lib/types.ts b/src/lib/types.ts index 72104352e..f512c50bc 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -30,6 +30,15 @@ export interface Auth { }; } +export interface PropertyFilter { + propertyName: string; + dataType: number; + operator: Operator; + value: string; +} + +export type EventPropertyFilter = PropertyFilter; + export interface Filter { name: string; operator: Operator; @@ -53,6 +62,43 @@ export interface DynamicData { [key: string]: number | string | number[] | string[]; } +export interface EventDataSeriesPoint { + x: string; + t: string; + y: number; +} + +export interface EventDataDateSeriesPoint { + t: string; + y: number; +} + +export interface EventDataNumericStats { + total: number; + average: number; + median: number; + max: number; + min: number; +} + +export interface SessionDataPivotRow { + sessionId: string; + distinctId: string; + createdAt: string | Date; + propertyKeys: string[]; + propertyValues: string[]; +} + +export interface PropertyLeaderboardRow { + label: string; + activity: number; + sessions: number; + visits: number; + views: number; + events: number; + totaltime: number; +} + export interface QueryOptions { joinSession?: boolean; columns?: Record; diff --git a/src/queries/prisma/website.ts b/src/queries/prisma/website.ts index 6c69431e7..ae7ea6c96 100644 --- a/src/queries/prisma/website.ts +++ b/src/queries/prisma/website.ts @@ -42,7 +42,7 @@ export async function getWebsites(criteria: Prisma.WebsiteFindManyArgs, filters: return attachShareIdToWebsites(websites); } -export async function getAllUserWebsitesIncludingTeamOwner(userId: string, filters?: QueryFilters) { +export async function getAllUserWebsitesIncludingTeamAccess(userId: string, filters?: QueryFilters) { return getWebsites( { where: { @@ -53,7 +53,7 @@ export async function getAllUserWebsitesIncludingTeamOwner(userId: string, filte deletedAt: null, members: { some: { - role: ROLES.teamOwner, + role: { in: [ROLES.teamOwner, ROLES.teamManager] }, userId, }, }, diff --git a/src/queries/sql/events/getEventDataArraySeries.ts b/src/queries/sql/events/getEventDataArraySeries.ts new file mode 100644 index 000000000..8e06e906c --- /dev/null +++ b/src/queries/sql/events/getEventDataArraySeries.ts @@ -0,0 +1,116 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataSeriesPoint, EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataArraySeries'; + +export async function getEventDataArraySeries( + ...args: [ + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + array_item.value as x, + ${getDateSQL('event_data.created_at', unit, timezone)} as t, + count(*) as y + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + cross join lateral jsonb_array_elements_text(coalesce(event_data.string_value, '[]')::jsonb) as array_item(value) + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + ${pfSQL} + group by 1, 2 + order by 2 + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + arrayJoin(JSONExtract(ifNull(event_data.string_value, '[]'), 'Array(String)')) as x, + ${getDateSQL('event_data.created_at', unit, timezone)} as t, + count() as y + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + ${pfSQL} + group by x, t + order by t + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/events/getEventDataDateSeries.ts b/src/queries/sql/events/getEventDataDateSeries.ts new file mode 100644 index 000000000..ac4ebff26 --- /dev/null +++ b/src/queries/sql/events/getEventDataDateSeries.ts @@ -0,0 +1,113 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataDateSeriesPoint, EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataDateSeries'; + +export async function getEventDataDateSeries( + ...args: [ + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getDateStringSQL, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + ${getDateStringSQL('event_data.date_value', 'second', timezone)} as t, + count(*) as y + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type = ${DATA_TYPE.date} + ${filterQuery} + ${pfSQL} + group by 1 + order by 1 + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getDateStringSQL, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + ${getDateStringSQL('event_data.date_value', 'second', timezone)} as t, + count() as y + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type = ${DATA_TYPE.date} + ${filterQuery} + ${pfSQL} + group by t + order by t + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/events/getEventDataEvents.ts b/src/queries/sql/events/getEventDataEvents.ts index f415e629d..313e8d97c 100644 --- a/src/queries/sql/events/getEventDataEvents.ts +++ b/src/queries/sql/events/getEventDataEvents.ts @@ -92,10 +92,10 @@ async function clickhouseQuery( return rawQuery( ` select - event_name as eventName, - data_key as propertyName, - data_type as dataType, - string_value as propertyValue, + event_data.event_name as eventName, + event_data.data_key as propertyName, + event_data.data_type as dataType, + event_data.string_value as propertyValue, count(*) as total from event_data any left join ( @@ -111,7 +111,11 @@ async function clickhouseQuery( where event_data.website_id = {websiteId:UUID} and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} ${filterQuery} - group by data_key, data_type, string_value, event_name + group by + event_data.data_key, + event_data.data_type, + event_data.string_value, + event_data.event_name order by 1 asc, 2 asc, 3 asc, 5 desc limit 500 `, @@ -123,9 +127,9 @@ async function clickhouseQuery( return rawQuery( ` select - event_name as eventName, - data_key as propertyName, - data_type as dataType, + event_data.event_name as eventName, + event_data.data_key as propertyName, + event_data.data_type as dataType, count(*) as total from event_data any left join ( @@ -141,7 +145,7 @@ async function clickhouseQuery( where event_data.website_id = {websiteId:UUID} and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} ${filterQuery} - group by data_key, data_type, event_name + group by event_data.data_key, event_data.data_type, event_data.event_name order by 1 asc, 2 asc limit 500 `, diff --git a/src/queries/sql/events/getEventDataFields.ts b/src/queries/sql/events/getEventDataFields.ts index 709454929..fe4f7b813 100644 --- a/src/queries/sql/events/getEventDataFields.ts +++ b/src/queries/sql/events/getEventDataFields.ts @@ -13,7 +13,7 @@ export async function getEventDataFields(...args: [websiteId: string, filters: Q } async function relationalQuery(websiteId: string, filters: QueryFilters) { - const { rawQuery, parseFilters, getDateSQL } = prisma; + const { rawQuery, parseFilters } = prisma; const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ ...filters, websiteId, @@ -24,11 +24,6 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { select data_key as "propertyName", data_type as "dataType", - case - when data_type = 2 then replace(string_value, '.0000', '') - when data_type = 4 then ${getDateSQL('date_value', 'hour')} - else string_value - end as "value", count(*) as "total" from event_data join website_event on website_event.event_id = event_data.website_event_id @@ -39,9 +34,8 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { where event_data.website_id = {{websiteId::uuid}} and event_data.created_at between {{startDate}} and {{endDate}} ${filterQuery} - group by data_key, data_type, value - order by 2 desc - limit 100 + group by data_key, data_type + order by "total" desc, "propertyName" asc `, queryParams, FUNCTION_NAME, @@ -51,7 +45,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { async function clickhouseQuery( websiteId: string, filters: QueryFilters, -): Promise<{ propertyName: string; dataType: number; propertyValue: string; total: number }[]> { +): Promise<{ propertyName: string; dataType: number; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId }); @@ -60,13 +54,10 @@ async function clickhouseQuery( select data_key as propertyName, data_type as dataType, - multiIf(data_type = 2, replaceAll(string_value, '.0000', ''), - data_type = 4, toString(date_trunc('hour', date_value)), - string_value) as "value", count(*) as "total" from event_data any left join ( - select * + select * from website_event where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} @@ -78,9 +69,8 @@ async function clickhouseQuery( where event_data.website_id = {websiteId:UUID} and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} ${filterQuery} - group by data_key, data_type, value - order by 2 desc - limit 100 + group by data_key, data_type + order by total desc, propertyName asc `, queryParams, FUNCTION_NAME, diff --git a/src/queries/sql/events/getEventDataNumericSeries.ts b/src/queries/sql/events/getEventDataNumericSeries.ts new file mode 100644 index 000000000..d9df94f54 --- /dev/null +++ b/src/queries/sql/events/getEventDataNumericSeries.ts @@ -0,0 +1,127 @@ +import clickhouse from '@/lib/clickhouse'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataNumericSeries'; + +export async function getEventDataNumericSeries( + ...args: [ + websiteId: string, + eventName: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +) { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +) { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + const aggSql = + metric === 'avg' + ? 'avg(cast(event_data.number_value as decimal))' + : metric === 'count' + ? 'count(*)' + : 'sum(cast(event_data.number_value as decimal))'; + + return rawQuery( + ` + select + ${getDateSQL('event_data.created_at', unit, timezone)} t, + ${aggSql} y + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type = 2 + ${filterQuery} + ${pfSQL} + group by 1 + order by 1 + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise<{ t: string; y: number }[]> { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + const aggSql = + metric === 'avg' + ? 'avg(event_data.number_value)' + : metric === 'count' + ? 'count()' + : 'sum(event_data.number_value)'; + + return rawQuery( + ` + select + ${getDateSQL('event_data.created_at', unit, timezone)} as t, + ${aggSql} as y + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type = 2 + ${filterQuery} + ${pfSQL} + group by t + order by t + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/events/getEventDataNumericStats.ts b/src/queries/sql/events/getEventDataNumericStats.ts new file mode 100644 index 000000000..5977ff3ac --- /dev/null +++ b/src/queries/sql/events/getEventDataNumericStats.ts @@ -0,0 +1,114 @@ +import clickhouse from '@/lib/clickhouse'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataNumericStats, EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataNumericStats'; + +export async function getEventDataNumericStats( + ...args: [ + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }).then(results => results?.[0]); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +) { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + coalesce(sum(cast(event_data.number_value as decimal)), 0) as "total", + coalesce(avg(cast(event_data.number_value as decimal)), 0) as "average", + coalesce(percentile_cont(0.5) within group (order by event_data.number_value), 0) as "median", + coalesce(max(event_data.number_value), 0) as "max", + coalesce(min(event_data.number_value), 0) as "min" + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type = 2 + ${filterQuery} + ${pfSQL} + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + if(count() = 0, 0, sum(event_data.number_value)) as total, + if(count() = 0, 0, avg(event_data.number_value)) as average, + if(count() = 0, 0, median(event_data.number_value)) as median, + if(count() = 0, 0, max(event_data.number_value)) as max, + if(count() = 0, 0, min(event_data.number_value)) as min + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type = 2 + ${filterQuery} + ${pfSQL} + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/events/getEventDataPivot.ts b/src/queries/sql/events/getEventDataPivot.ts new file mode 100644 index 000000000..8699d3269 --- /dev/null +++ b/src/queries/sql/events/getEventDataPivot.ts @@ -0,0 +1,234 @@ +import clickhouse from '@/lib/clickhouse'; +import { DEFAULT_PAGE_SIZE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataPivot'; + +export async function getEventDataPivot( + ...args: [ + websiteId: string, + eventName: string, + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +) { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +) { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery, getDateStringSQL } = prisma; + const { page = 1, pageSize } = filters; + const size = +pageSize || DEFAULT_PAGE_SIZE; + const offset = +size * (+page - 1); + + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + const countResult = await rawQuery( + ` + select count(distinct website_event.event_id) as num + from website_event + join event_data on event_data.website_event_id = website_event.event_id + and event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_name = {{eventName}} + ${filterQuery} + ${pfSQL} + `, + { ...queryParams, eventName, ...pfParams }, + ); + + const count = countResult[0].num; + + const rows = await rawQuery( + ` + with paged_events as ( + select website_event.event_id + from website_event + join event_data on event_data.website_event_id = website_event.event_id + and event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_name = {{eventName}} + ${filterQuery} + ${pfSQL} + group by website_event.event_id + order by max(website_event.created_at) desc + limit ${size} offset ${offset} + ) + select + website_event.event_id as "eventId", + website_event.session_id as "sessionId", + website_event.event_name as "eventName", + website_event.url_path as "urlPath", + website_event.created_at as "createdAt", + event_data.data_key as "dataKey", + coalesce( + case when event_data.data_type = 1 then event_data.string_value end, + case when event_data.data_type = 2 then cast(event_data.number_value as varchar) end, + case when event_data.data_type = 3 then event_data.string_value end, + case when event_data.data_type = 4 then ${getDateStringSQL('event_data.date_value', 'second', timezone)} end, + case when event_data.data_type = 5 then event_data.string_value end, + '' + ) as "value", + event_data.data_type as "dataType" + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + join paged_events on paged_events.event_id = event_data.website_event_id + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + order by website_event.created_at desc + `, + { ...queryParams, eventName, ...pfParams }, + FUNCTION_NAME, + ); + + // Pivot flat rows into one record per event + const eventMap = new Map< + string, + { + eventId: string; + sessionId: string; + eventName: string; + urlPath: string; + createdAt: Date; + propertyKeys: string[]; + propertyValues: string[]; + } + >(); + for (const { eventId, sessionId, eventName: name, urlPath, createdAt, dataKey, value } of rows) { + if (!eventMap.has(eventId)) { + eventMap.set(eventId, { + eventId, + sessionId, + eventName: name, + urlPath, + createdAt, + propertyKeys: [], + propertyValues: [], + }); + } + const entry = eventMap.get(eventId); + entry.propertyKeys.push(dataKey); + entry.propertyValues.push(value ?? ''); + } + + return { data: [...eventMap.values()], count, page: +page, pageSize: size }; +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +) { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery, getDateStringSQL } = clickhouse; + const { page = 1, pageSize } = filters; + const size = +pageSize || DEFAULT_PAGE_SIZE; + const offset = +size * (+page - 1); + + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + const count = await rawQuery( + ` + select count() as num + from umami.event_data_pivot + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data_pivot.event_id + and website_event.session_id = event_data_pivot.session_id + and website_event.website_id = event_data_pivot.website_id + ${cohortQuery} + where event_data_pivot.website_id = {websiteId:UUID} + and event_data_pivot.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data_pivot.event_name = {eventName:String} + ${filterQuery} + ${pfSQL} + `, + { ...queryParams, eventName, ...pfParams }, + ).then((res: any) => res[0].num); + + const data = await rawQuery( + ` + select + event_data_pivot.event_id as eventId, + event_data_pivot.session_id as sessionId, + event_data_pivot.event_name as eventName, + event_data_pivot.url_path as urlPath, + event_data_pivot.created_at as createdAt, + groupArrayMerge(property_keys) as propertyKeys, + arrayMap( + (value, dataType) -> if( + dataType = 4, + ${getDateStringSQL('parseDateTimeBestEffortOrNull(value)', 'second', timezone)}, + value + ), + groupArrayMerge(property_values), + groupArrayMerge(property_types) + ) as propertyValues + from umami.event_data_pivot + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data_pivot.event_id + and website_event.session_id = event_data_pivot.session_id + and website_event.website_id = event_data_pivot.website_id + ${cohortQuery} + where event_data_pivot.website_id = {websiteId:UUID} + and event_data_pivot.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data_pivot.event_name = {eventName:String} + ${filterQuery} + ${pfSQL} + group by + event_data_pivot.event_id, + event_data_pivot.session_id, + event_data_pivot.event_name, + event_data_pivot.url_path, + event_data_pivot.created_at + order by event_data_pivot.created_at desc + limit ${size} offset ${offset} + `, + { ...queryParams, eventName, ...pfParams }, + FUNCTION_NAME, + ); + + return { data, count, page: +page, pageSize: size }; +} diff --git a/src/queries/sql/events/getEventDataProperties.ts b/src/queries/sql/events/getEventDataProperties.ts index 82d0b6b62..943dca84d 100644 --- a/src/queries/sql/events/getEventDataProperties.ts +++ b/src/queries/sql/events/getEventDataProperties.ts @@ -31,6 +31,7 @@ async function relationalQuery( select website_event.event_name as "eventName", event_data.data_key as "propertyName", + event_data.data_type as "dataType", count(*) as "total" from event_data join website_event on website_event.event_id = event_data.website_event_id @@ -41,8 +42,8 @@ async function relationalQuery( where event_data.website_id = {{websiteId::uuid}} and event_data.created_at between {{startDate}} and {{endDate}} ${filterQuery} - group by website_event.event_name, event_data.data_key - order by 3 desc + group by website_event.event_name, event_data.data_key, event_data.data_type + order by 4 desc limit 500 `, queryParams, @@ -53,7 +54,7 @@ async function relationalQuery( async function clickhouseQuery( websiteId: string, filters: QueryFilters & { propertyName?: string }, -): Promise<{ eventName: string; propertyName: string; total: number }[]> { +): Promise<{ eventName: string; propertyName: string; dataType: number; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; const { filterQuery, cohortQuery, queryParams } = parseFilters( { ...filters, websiteId }, @@ -65,8 +66,9 @@ async function clickhouseQuery( return rawQuery( ` select - event_name as eventName, - data_key as propertyName, + event_data.event_name as eventName, + event_data.data_key as propertyName, + event_data.data_type as dataType, count(*) as total from event_data any left join ( @@ -82,8 +84,8 @@ async function clickhouseQuery( where event_data.website_id = {websiteId:UUID} and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} ${filterQuery} - group by event_name, data_key - order by 1, 3 desc + group by event_data.event_name, event_data.data_key, event_data.data_type + order by 1, 4 desc limit 500 `, queryParams, diff --git a/src/queries/sql/events/getEventDataPropertySeries.ts b/src/queries/sql/events/getEventDataPropertySeries.ts new file mode 100644 index 000000000..7cc7071c6 --- /dev/null +++ b/src/queries/sql/events/getEventDataPropertySeries.ts @@ -0,0 +1,115 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataSeriesPoint, EventPropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getEventDataPropertySeries'; + +export async function getEventDataPropertySeries( + ...args: [ + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters?: EventPropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + event_data.string_value as x, + ${getDateSQL('event_data.created_at', unit, timezone)} t, + count(*) y + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type in (${DATA_TYPE.string}, ${DATA_TYPE.boolean}) + ${filterQuery} + ${pfSQL} + group by 1, 2 + order by 2 + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + eventName: string, + propertyName: string, + filters: QueryFilters, + eventFilters: EventPropertyFilter[] = [], +): Promise { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(eventFilters, 'event', timezone); + + return rawQuery( + ` + select + event_data.string_value as x, + ${getDateSQL('event_data.created_at', unit, timezone)} as t, + count() as y + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type in (${DATA_TYPE.string}, ${DATA_TYPE.boolean}) + ${filterQuery} + ${pfSQL} + group by x, t + order by t + `, + { ...queryParams, eventName, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/events/getEventDataValues.ts b/src/queries/sql/events/getEventDataValues.ts index f644934e3..70e134e5b 100644 --- a/src/queries/sql/events/getEventDataValues.ts +++ b/src/queries/sql/events/getEventDataValues.ts @@ -1,4 +1,5 @@ import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import type { QueryFilters } from '@/lib/types'; @@ -11,7 +12,11 @@ interface WebsiteEventData { } export async function getEventDataValues( - ...args: [websiteId: string, filters: QueryFilters & { propertyName?: string }] + ...args: [ + websiteId: string, + eventName: string, + filters: QueryFilters & { propertyName?: string; dataType?: number }, + ] ): Promise { return runQuery({ [PRISMA]: () => relationalQuery(...args), @@ -21,20 +26,51 @@ export async function getEventDataValues( async function relationalQuery( websiteId: string, - filters: QueryFilters & { propertyName?: string }, + eventName: string, + filters: QueryFilters & { propertyName?: string; dataType?: number }, ) { const { rawQuery, parseFilters, getDateSQL } = prisma; + const { dataType } = filters; const { filterQuery, joinSessionQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, }); + if (dataType === DATA_TYPE.array) { + return rawQuery( + ` + select + array_item.value as "value", + count(*) as "total" + from event_data + join website_event on website_event.event_id = event_data.website_event_id + and website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} + cross join lateral jsonb_array_elements_text(coalesce(event_data.string_value, '[]')::jsonb) as array_item(value) + ${cohortQuery} + ${joinSessionQuery} + where event_data.website_id = {{websiteId::uuid}} + and event_data.created_at between {{startDate}} and {{endDate}} + and event_data.data_key = {{propertyName}} + and event_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + group by array_item.value + order by 2 desc + limit 100 + `, + { ...queryParams, eventName }, + FUNCTION_NAME, + ); + } + return rawQuery( ` select - case - when data_type = 2 then replace(string_value, '.0000', '') - when data_type = 4 then ${getDateSQL('date_value', 'hour')} + case + when data_type = 2 then replace(string_value, '.0000', '') + when data_type = 4 then ${getDateSQL('date_value', 'hour')} else string_value end as "value", count(*) as "total" @@ -42,28 +78,66 @@ async function relationalQuery( join website_event on website_event.event_id = event_data.website_event_id and website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} + and website_event.event_type = 2 + and website_event.event_name = {{eventName}} ${cohortQuery} ${joinSessionQuery} where event_data.website_id = {{websiteId::uuid}} and event_data.created_at between {{startDate}} and {{endDate}} and event_data.data_key = {{propertyName}} + ${dataType ? `and event_data.data_type = ${dataType}` : ''} ${filterQuery} group by value order by 2 desc limit 100 `, - queryParams, + { ...queryParams, eventName }, FUNCTION_NAME, ); } async function clickhouseQuery( websiteId: string, - filters: QueryFilters & { propertyName?: string }, + eventName: string, + filters: QueryFilters & { propertyName?: string; dataType?: number }, ): Promise<{ value: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; + const { dataType } = filters; const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId }); + if (dataType === DATA_TYPE.array) { + return rawQuery( + ` + select + arrayJoin(JSONExtract(ifNull(event_data.string_value, '[]'), 'Array(String)')) as "value", + count(*) as "total" + from event_data + any left join ( + select * + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = 2 + and event_name = {eventName:String}) website_event + on website_event.event_id = event_data.event_id + and website_event.session_id = event_data.session_id + and website_event.website_id = event_data.website_id + ${cohortQuery} + where event_data.website_id = {websiteId:UUID} + and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} + and event_data.data_key = {propertyName:String} + and event_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + group by value + order by 2 desc + limit 100 + `, + { ...queryParams, eventName }, + FUNCTION_NAME, + ); + } + return rawQuery( ` select @@ -71,26 +145,29 @@ async function clickhouseQuery( data_type = 4, toString(date_trunc('hour', date_value)), string_value) as "value", count(*) as "total" - from event_data + from event_data any left join ( - select * + select * from website_event where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and event_type = 2) website_event + and event_type = 2 + and event_name = {eventName:String}) website_event on website_event.event_id = event_data.event_id and website_event.session_id = event_data.session_id and website_event.website_id = event_data.website_id ${cohortQuery} where event_data.website_id = {websiteId:UUID} and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_data.event_name = {eventName:String} and event_data.data_key = {propertyName:String} + ${dataType ? `and event_data.data_type = ${dataType}` : ''} ${filterQuery} group by value order by 2 desc limit 100 `, - queryParams, + { ...queryParams, eventName }, FUNCTION_NAME, ); } diff --git a/src/queries/sql/getValues.ts b/src/queries/sql/getValues.ts index 8573335bf..908be4126 100644 --- a/src/queries/sql/getValues.ts +++ b/src/queries/sql/getValues.ts @@ -1,8 +1,13 @@ import clickhouse from '@/lib/clickhouse'; +import { FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import type { QueryFilters } from '@/lib/types'; +const SESSION_DB_COLUMNS = new Set( + SESSION_COLUMNS.map(col => FILTER_COLUMNS[col as keyof typeof FILTER_COLUMNS]).filter(Boolean), +); + const FUNCTION_NAME = 'getValues'; export async function getValues( @@ -45,13 +50,27 @@ async function relationalQuery(websiteId: string, column: string, filters: Query } } + if (SESSION_DB_COLUMNS.has(column)) { + return rawQuery( + ` + select ${column} as "value", count(*) as "count" + from session + where website_id = {{websiteId::uuid}} + and created_at between {{startDate}} and {{endDate}} + ${searchQuery} + group by 1 + order by 2 desc + limit 10 + `, + { websiteId, startDate, endDate, search: `%${search}%`, ...params }, + FUNCTION_NAME, + ); + } + return rawQuery( ` select ${column} as "value", count(*) as "count" from website_event - inner join session - on session.session_id = website_event.session_id - and session.website_id = website_event.website_id where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} ${searchQuery} @@ -60,13 +79,7 @@ async function relationalQuery(websiteId: string, column: string, filters: Query order by 2 desc limit 10 `, - { - websiteId, - startDate, - endDate, - search: `%${search}%`, - ...params, - }, + { websiteId, startDate, endDate, search: `%${search}%`, ...params }, FUNCTION_NAME, ); } diff --git a/src/queries/sql/index.ts b/src/queries/sql/index.ts index 0b164a458..380565471 100644 --- a/src/queries/sql/index.ts +++ b/src/queries/sql/index.ts @@ -1,7 +1,13 @@ +export * from './events/getEventDataArraySeries'; export * from './events/getEventDataById'; +export * from './events/getEventDataDateSeries'; export * from './events/getEventDataEvents'; export * from './events/getEventDataFields'; +export * from './events/getEventDataNumericSeries'; +export * from './events/getEventDataNumericStats'; +export * from './events/getEventDataPivot'; export * from './events/getEventDataProperties'; +export * from './events/getEventDataPropertySeries'; export * from './events/getEventDataStats'; export * from './events/getEventDataUsage'; export * from './events/getEventDataValues'; @@ -35,7 +41,14 @@ export * from './reports/getUTM'; export * from './sessions/createSession'; export * from './sessions/getSessionActivity'; export * from './sessions/getSessionData'; +export * from './sessions/getSessionDataArraySeries'; +export * from './sessions/getSessionDataDateSeries'; export * from './sessions/getSessionDataProperties'; +export * from './sessions/getSessionDataPropertySeries'; +export * from './sessions/getSessionDataNumericSeries'; +export * from './sessions/getSessionDataNumericStats'; +export * from './sessions/getSessionDataPivot'; +export * from './sessions/getSessionDataActivityStats'; export * from './sessions/getSessionDataValues'; export * from './sessions/getSessionExpandedMetrics'; export * from './sessions/getSessionMetrics'; diff --git a/src/queries/sql/replays/getSessionReplays.ts b/src/queries/sql/replays/getSessionReplays.ts index d7e1535b6..8678f21b1 100644 --- a/src/queries/sql/replays/getSessionReplays.ts +++ b/src/queries/sql/replays/getSessionReplays.ts @@ -17,7 +17,7 @@ export function getSessionReplays( async function relationalQuery(websiteId: string, filters: QueryFilters, sessionId?: string) { const { pagedRawQuery, parseFilters } = prisma; const { search } = filters; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ + const { filterQuery, cohortQuery, queryParams, joinSessionQuery } = parseFilters({ ...filters, websiteId, search: search ? `%${search}%` : undefined, @@ -27,6 +27,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, session filterQuery || cohortQuery ? `join (select distinct website_event.website_id, website_event.session_id, website_event.visit_id from website_event + ${joinSessionQuery} ${cohortQuery} where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} diff --git a/src/queries/sql/reports/getFunnel.ts b/src/queries/sql/reports/getFunnel.ts index b1b55c2b3..72148ae43 100644 --- a/src/queries/sql/reports/getFunnel.ts +++ b/src/queries/sql/reports/getFunnel.ts @@ -292,8 +292,8 @@ async function clickhouseQuery( select distinct y.session_id as session_id, y.url_path as url_path, y.referrer_path as referrer_path, - y.event_name, - y.event_id, + y.event_name as event_name, + y.event_id as event_id, y.created_at as created_at from level${i} x join level0 y diff --git a/src/queries/sql/reports/getPerformance.ts b/src/queries/sql/reports/getPerformance.ts index 9aaaffd9d..1abe9c54a 100644 --- a/src/queries/sql/reports/getPerformance.ts +++ b/src/queries/sql/reports/getPerformance.ts @@ -47,7 +47,7 @@ async function relationalQuery( const chart = await rawQuery( ` select - ${getDateSQL('created_at', unit, timezone)} t, + ${getDateSQL('website_event.created_at', unit, timezone)} t, percentile_cont(0.5) within group (order by ${metric}) as p50, percentile_cont(0.75) within group (order by ${metric}) as p75, percentile_cont(0.95) within group (order by ${metric}) as p95 diff --git a/src/queries/sql/sessions/getSessionDataActivityStats.ts b/src/queries/sql/sessions/getSessionDataActivityStats.ts new file mode 100644 index 000000000..3da98140b --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataActivityStats.ts @@ -0,0 +1,181 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { PropertyFilter, PropertyLeaderboardRow, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataActivityStats'; + +export async function getSessionDataActivityStats( + ...args: [websiteId: string, propertyName: string, filters: QueryFilters, propertyFilters?: PropertyFilter[]] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +) { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery, getTimestampDiffSQL } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id, website_event.website_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ), + session_rollup as ( + select + website_event.session_id, + website_event.visit_id, + count(*) as activity, + sum(case when website_event.event_type = 1 then 1 else 0 end) as views, + sum(case when website_event.event_type = 2 then 1 else 0 end) as events, + min(website_event.created_at) as min_time, + max(website_event.created_at) as max_time + from website_event + join filtered_sessions + on filtered_sessions.session_id = website_event.session_id + and filtered_sessions.website_id = website_event.website_id + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + group by website_event.session_id, website_event.visit_id + ), + session_stats as ( + select + session_id, + count(*) as visits, + sum(activity) as activity, + sum(views) as views, + sum(events) as events, + sum(${getTimestampDiffSQL('min_time', 'max_time')}) as totaltime + from session_rollup + group by session_id + ), + property_values as ( + select + session_data.session_id, + session_data.string_value as value + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + and filtered_sessions.website_id = session_data.website_id + where session_data.website_id = {{websiteId::uuid}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = ${DATA_TYPE.string} + and coalesce(session_data.string_value, '') != '' + ) + select + property_values.value as label, + coalesce(sum(session_stats.activity), 0) as activity, + count(distinct property_values.session_id) as sessions, + coalesce(sum(session_stats.visits), 0) as visits, + coalesce(sum(session_stats.views), 0) as views, + coalesce(sum(session_stats.events), 0) as events, + coalesce(sum(session_stats.totaltime), 0) as totaltime + from property_values + join session_stats on session_stats.session_id = property_values.session_id + group by property_values.value + order by activity desc, property_values.value asc + limit 100 + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +) { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ), + session_rollup as ( + select + website_event.session_id, + website_event.visit_id, + count() as activity, + sumIf(1, website_event.event_type = 1) as views, + sumIf(1, website_event.event_type = 2) as events, + min(website_event.created_at) as min_time, + max(website_event.created_at) as max_time + from website_event + join filtered_sessions on filtered_sessions.session_id = website_event.session_id + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + group by website_event.session_id, website_event.visit_id + ), + session_stats as ( + select + session_id, + count() as visits, + sum(activity) as activity, + sum(views) as views, + sum(events) as events, + sum(max_time - min_time) as totaltime + from session_rollup + group by session_id + ), + property_values as ( + select + session_data.session_id, + session_data.string_value as value + from session_data final + join filtered_sessions on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {websiteId:UUID} + and session_data.data_key = {propertyName:String} + and session_data.data_type = ${DATA_TYPE.string} + and ifNull(session_data.string_value, '') != '' + ) + select + property_values.value as label, + ifNull(sum(session_stats.activity), 0) as activity, + uniq(property_values.session_id) as sessions, + ifNull(sum(session_stats.visits), 0) as visits, + ifNull(sum(session_stats.views), 0) as views, + ifNull(sum(session_stats.events), 0) as events, + ifNull(sum(session_stats.totaltime), 0) as totaltime + from property_values + join session_stats on session_stats.session_id = property_values.session_id + group by property_values.value + order by activity desc, property_values.value asc + limit 100 + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataArraySeries.ts b/src/queries/sql/sessions/getSessionDataArraySeries.ts new file mode 100644 index 000000000..a4b81ecb1 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataArraySeries.ts @@ -0,0 +1,99 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataSeriesPoint, PropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataArraySeries'; + +export async function getSessionDataArraySeries( + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + array_item.value as x, + ${getDateSQL('session_data.created_at', unit, timezone)} as t, + count(distinct session_data.session_id) as y + from website_event + ${cohortQuery} + ${joinSessionQuery} + join session_data + on session_data.session_id = website_event.session_id + and session_data.website_id = website_event.website_id + cross join lateral jsonb_array_elements_text(coalesce(session_data.string_value, '[]')::jsonb) as array_item(value) + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + ${pfSQL} + group by 1, 2 + order by 2 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + arrayJoin(JSONExtract(ifNull(session_data.string_value, '[]'), 'Array(String)')) as x, + ${getDateSQL('session_data.created_at', unit, timezone)} as t, + uniq(session_data.session_id) as y + from website_event + ${cohortQuery} + join session_data final + on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and session_data.data_key = {propertyName:String} + and session_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + ${pfSQL} + group by x, t + order by t + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataDateSeries.ts b/src/queries/sql/sessions/getSessionDataDateSeries.ts new file mode 100644 index 000000000..d74b5e8a8 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataDateSeries.ts @@ -0,0 +1,96 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataDateSeriesPoint, PropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataDateSeries'; + +export async function getSessionDataDateSeries( + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getDateStringSQL, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + ${getDateStringSQL('session_data.date_value', 'second', timezone)} as t, + count(distinct session_data.session_id) as y + from website_event + ${cohortQuery} + ${joinSessionQuery} + join session_data + on session_data.session_id = website_event.session_id + and session_data.website_id = website_event.website_id + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = ${DATA_TYPE.date} + ${filterQuery} + ${pfSQL} + group by 1 + order by 1 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getDateStringSQL, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + ${getDateStringSQL('session_data.date_value', 'second', timezone)} as t, + uniq(session_data.session_id) as y + from website_event + ${cohortQuery} + join session_data final + on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and session_data.data_key = {propertyName:String} + and session_data.data_type = ${DATA_TYPE.date} + ${filterQuery} + ${pfSQL} + group by t + order by t + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataNumericSeries.ts b/src/queries/sql/sessions/getSessionDataNumericSeries.ts new file mode 100644 index 000000000..03d660f02 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataNumericSeries.ts @@ -0,0 +1,119 @@ +import clickhouse from '@/lib/clickhouse'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { PropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataNumericSeries'; + +export async function getSessionDataNumericSeries( + ...args: [ + websiteId: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +) { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +) { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const aggSql = + metric === 'avg' + ? 'avg(cast(session_data.number_value as decimal))' + : metric === 'count' + ? 'count(distinct session_data.session_id)' + : 'sum(cast(session_data.number_value as decimal))'; + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id, website_event.website_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ) + select + ${getDateSQL('session_data.created_at', unit, timezone)} t, + ${aggSql} y + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + and filtered_sessions.website_id = session_data.website_id + where session_data.website_id = {{websiteId::uuid}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = 2 + group by 1 + order by 1 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + metric: 'sum' | 'avg' | 'count', + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise<{ t: string; y: number }[]> { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + const aggSql = + metric === 'avg' + ? 'avg(session_data.number_value)' + : metric === 'count' + ? 'uniq(session_data.session_id)' + : 'sum(session_data.number_value)'; + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ) + select + ${getDateSQL('session_data.created_at', unit, timezone)} as t, + ${aggSql} as y + from session_data final + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {websiteId:UUID} + and session_data.data_key = {propertyName:String} + and session_data.data_type = 2 + group by t + order by t + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataNumericStats.ts b/src/queries/sql/sessions/getSessionDataNumericStats.ts new file mode 100644 index 000000000..a7dcd7df0 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataNumericStats.ts @@ -0,0 +1,106 @@ +import clickhouse from '@/lib/clickhouse'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataNumericStats, PropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataNumericStats'; + +export async function getSessionDataNumericStats( + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }).then(results => results?.[0]); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +) { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id, website_event.website_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ) + select + coalesce(sum(cast(session_data.number_value as decimal)), 0) as "total", + coalesce(avg(cast(session_data.number_value as decimal)), 0) as "average", + coalesce(percentile_cont(0.5) within group (order by session_data.number_value), 0) as "median", + coalesce(max(session_data.number_value), 0) as "max", + coalesce(min(session_data.number_value), 0) as "min" + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + and filtered_sessions.website_id = session_data.website_id + where session_data.website_id = {{websiteId::uuid}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = 2 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ) + select + if(count() = 0, 0, sum(session_data.number_value)) as total, + if(count() = 0, 0, avg(session_data.number_value)) as average, + if(count() = 0, 0, median(session_data.number_value)) as median, + if(count() = 0, 0, max(session_data.number_value)) as max, + if(count() = 0, 0, min(session_data.number_value)) as min + from session_data final + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {websiteId:UUID} + and session_data.data_key = {propertyName:String} + and session_data.data_type = 2 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataPivot.ts b/src/queries/sql/sessions/getSessionDataPivot.ts new file mode 100644 index 000000000..ac4528123 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataPivot.ts @@ -0,0 +1,281 @@ +import clickhouse from '@/lib/clickhouse'; +import { DEFAULT_PAGE_SIZE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { PageResult, PropertyFilter, QueryFilters, SessionDataPivotRow } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataPivot'; + +export async function getSessionDataPivot( + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +): Promise> { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise> { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery, getDateStringSQL } = prisma; + const { page = 1, pageSize } = filters; + const size = +pageSize || DEFAULT_PAGE_SIZE; + const offset = +size * (+page - 1); + + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); + + const countResult = (await rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ), + latest_session_properties as ( + select + ranked.session_id, + ranked.data_key + from ( + select + session_data.session_id, + session_data.data_key, + row_number() over ( + partition by session_data.session_id, session_data.data_key + order by session_data.created_at desc, session_data.session_data_id desc + ) as row_num + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {{websiteId::uuid}} + ) ranked + where ranked.row_num = 1 + ) + select count(*) as num + from latest_session_properties + where latest_session_properties.data_key = {{propertyName}} + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + )) as { num: number }[]; + + const count = countResult[0].num; + + const rows = (await rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ), + latest_session_properties as ( + select + ranked.session_id, + ranked.distinct_id, + ranked.created_at, + ranked.data_key, + ranked.data_type, + ranked.string_value, + ranked.number_value, + ranked.date_value + from ( + select + session_data.session_id, + session_data.distinct_id, + session_data.created_at, + session_data.data_key, + session_data.data_type, + session_data.string_value, + session_data.number_value, + session_data.date_value, + row_number() over ( + partition by session_data.session_id, session_data.data_key + order by session_data.created_at desc, session_data.session_data_id desc + ) as row_num + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {{websiteId::uuid}} + ) ranked + where ranked.row_num = 1 + ), + paged_sessions as ( + select + latest_session_properties.session_id, + latest_session_properties.created_at as sort_created_at + from latest_session_properties + where latest_session_properties.data_key = {{propertyName}} + order by latest_session_properties.created_at desc + limit ${size} offset ${offset} + ) + select + latest_session_properties.session_id as "sessionId", + coalesce(max(latest_session_properties.distinct_id), '') as "distinctId", + max(latest_session_properties.created_at) as "createdAt", + array_agg(latest_session_properties.data_key order by latest_session_properties.data_key asc) as "propertyKeys", + array_agg( + coalesce( + case when latest_session_properties.data_type = 1 then latest_session_properties.string_value end, + case when latest_session_properties.data_type = 2 then cast(latest_session_properties.number_value as varchar) end, + case when latest_session_properties.data_type = 3 then latest_session_properties.string_value end, + case when latest_session_properties.data_type = 4 then ${getDateStringSQL('latest_session_properties.date_value', 'second', timezone)} end, + case when latest_session_properties.data_type = 5 then latest_session_properties.string_value end, + '' + ) + order by latest_session_properties.data_key asc + ) as "propertyValues" + from latest_session_properties + join paged_sessions + on paged_sessions.session_id = latest_session_properties.session_id + group by latest_session_properties.session_id, paged_sessions.sort_created_at + order by paged_sessions.sort_created_at desc + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + FUNCTION_NAME, + )) as SessionDataPivotRow[]; + + return { data: rows, count, page: +page, pageSize: size }; +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise> { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery, getDateStringSQL } = clickhouse; + const { page = 1, pageSize } = filters; + const size = +pageSize || DEFAULT_PAGE_SIZE; + const offset = +size * (+page - 1); + + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); + + const countResult = (await rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ), + latest_session_properties as ( + select + session_data.session_id as session_id, + session_data.data_key as data_key + from session_data final + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {websiteId:UUID} + group by + session_data.session_id, + session_data.data_key + ) + select count() as num + from latest_session_properties + where latest_session_properties.data_key = {propertyName:String} + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + )) as { num: number }[]; + const count = countResult[0].num; + + const data = (await rawQuery( + ` + with filtered_sessions as ( + select distinct website_event.session_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ), + latest_session_properties as ( + select + session_data.session_id as session_id, + argMax(ifNull(session_data.distinct_id, ''), session_data.created_at) as distinct_id, + session_data.data_key as data_key, + argMax(session_data.data_type, session_data.created_at) as data_type, + argMax(session_data.string_value, session_data.created_at) as string_value, + argMax(session_data.number_value, session_data.created_at) as number_value, + argMax(session_data.date_value, session_data.created_at) as date_value, + max(session_data.created_at) as created_at + from session_data final + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + where session_data.website_id = {websiteId:UUID} + group by + session_data.session_id, + session_data.data_key + ), + paged_sessions as ( + select + latest_session_properties.session_id, + latest_session_properties.created_at as sort_created_at + from latest_session_properties + where latest_session_properties.data_key = {propertyName:String} + order by latest_session_properties.created_at desc + limit ${size} offset ${offset} + ) + select + latest_session_properties.session_id as sessionId, + max(latest_session_properties.distinct_id) as distinctId, + max(latest_session_properties.created_at) as createdAt, + groupArray(latest_session_properties.data_key) as propertyKeys, + groupArray( + multiIf( + latest_session_properties.data_type IN (1, 3, 5), ifNull(latest_session_properties.string_value, ''), + latest_session_properties.data_type = 2, toString(ifNull(latest_session_properties.number_value, 0)), + latest_session_properties.data_type = 4, ${getDateStringSQL('latest_session_properties.date_value', 'second', timezone)}, + '' + ) + ) as propertyValues + from latest_session_properties + join paged_sessions + on paged_sessions.session_id = latest_session_properties.session_id + group by + latest_session_properties.session_id, + paged_sessions.sort_created_at + order by paged_sessions.sort_created_at desc + `, + { ...queryParams, websiteId, propertyName, ...pfParams }, + FUNCTION_NAME, + )) as SessionDataPivotRow[]; + + return { data, count, page: +page, pageSize: size }; +} diff --git a/src/queries/sql/sessions/getSessionDataProperties.ts b/src/queries/sql/sessions/getSessionDataProperties.ts index 9b429f9b9..446d8e465 100644 --- a/src/queries/sql/sessions/getSessionDataProperties.ts +++ b/src/queries/sql/sessions/getSessionDataProperties.ts @@ -1,12 +1,17 @@ import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; -import type { QueryFilters } from '@/lib/types'; +import type { PropertyFilter, QueryFilters } from '@/lib/types'; const FUNCTION_NAME = 'getSessionDataProperties'; export async function getSessionDataProperties( - ...args: [websiteId: string, filters: QueryFilters] + ...args: [ + websiteId: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + selectedPropertyName?: string, + ] ) { return runQuery({ [PRISMA]: () => relationalQuery(...args), @@ -14,32 +19,58 @@ export async function getSessionDataProperties( }); } -async function relationalQuery(websiteId: string, filters: QueryFilters) { - const { rawQuery, parseFilters } = prisma; +async function relationalQuery( + websiteId: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], + selectedPropertyName?: string, +) { + const { timezone = 'utc' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = prisma; const { filterQuery, joinSessionQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, + timezone, }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` + with filtered_sessions as ( + select distinct website_event.session_id, website_event.website_id + from website_event + ${cohortQuery} + ${joinSessionQuery} + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + ${filterQuery} + ${pfSQL} + ), + selected_property_sessions as ( + select distinct session_data.session_id, session_data.website_id + from session_data + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + and filtered_sessions.website_id = session_data.website_id + ${selectedPropertyName ? 'where session_data.data_key = {{selectedPropertyName}}' : ''} + ) select data_key as "propertyName", + data_type as "dataType", count(distinct session_data.session_id) as "total" - from website_event - ${cohortQuery} - ${joinSessionQuery} + from selected_property_sessions join session_data - on session_data.session_id = website_event.session_id - and session_data.website_id = website_event.website_id - where website_event.website_id = {{websiteId::uuid}} - and website_event.created_at between {{startDate}} and {{endDate}} - ${filterQuery} - group by 1 - order by 2 desc + on session_data.session_id = selected_property_sessions.session_id + and session_data.website_id = selected_property_sessions.website_id + group by 1, 2 + order by 3 desc, 1 asc limit 500 `, - queryParams, + { ...queryParams, websiteId, selectedPropertyName, ...pfParams }, FUNCTION_NAME, ); } @@ -47,29 +78,52 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { async function clickhouseQuery( websiteId: string, filters: QueryFilters, -): Promise<{ propertyName: string; total: number }[]> { - const { rawQuery, parseFilters } = clickhouse; - const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId }); + propertyFilters: PropertyFilter[] = [], + selectedPropertyName?: string, +): Promise<{ propertyName: string; dataType: number; total: number }[]> { + const { timezone = 'UTC' } = filters; + const { rawQuery, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery( + propertyFilters, + 'session', + timezone, + ); return rawQuery( ` + with filtered_sessions as ( + select distinct website_event.session_id, website_event.website_id + from website_event + ${cohortQuery} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + ${filterQuery} + ${pfSQL} + ), + selected_property_sessions as ( + select distinct session_data.session_id, session_data.website_id + from session_data final + join filtered_sessions + on filtered_sessions.session_id = session_data.session_id + and filtered_sessions.website_id = session_data.website_id + ${selectedPropertyName ? 'where session_data.data_key = {selectedPropertyName:String}' : ''} + ) select data_key as propertyName, + data_type as dataType, count(distinct session_data.session_id) as total - from website_event - ${cohortQuery} + from selected_property_sessions join session_data final - on session_data.session_id = website_event.session_id - and session_data.website_id = {websiteId:UUID} - where website_event.website_id = {websiteId:UUID} - and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + on session_data.session_id = selected_property_sessions.session_id + and session_data.website_id = selected_property_sessions.website_id + where session_data.website_id = {websiteId:UUID} and session_data.data_key != '' - ${filterQuery} - group by 1 - order by 2 desc + group by 1, 2 + order by 3 desc, 1 asc limit 500 `, - queryParams, + { ...queryParams, websiteId, selectedPropertyName, ...pfParams }, FUNCTION_NAME, ); } diff --git a/src/queries/sql/sessions/getSessionDataPropertySeries.ts b/src/queries/sql/sessions/getSessionDataPropertySeries.ts new file mode 100644 index 000000000..fdffab423 --- /dev/null +++ b/src/queries/sql/sessions/getSessionDataPropertySeries.ts @@ -0,0 +1,98 @@ +import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import prisma from '@/lib/prisma'; +import type { EventDataSeriesPoint, PropertyFilter, QueryFilters } from '@/lib/types'; + +const FUNCTION_NAME = 'getSessionDataPropertySeries'; + +export async function getSessionDataPropertySeries( + ...args: [ + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters?: PropertyFilter[], + ] +): Promise { + return runQuery({ + [PRISMA]: () => relationalQuery(...args), + [CLICKHOUSE]: () => clickhouseQuery(...args), + }); +} + +async function relationalQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'utc', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = prisma; + const { filterQuery, cohortQuery, joinSessionQuery, queryParams } = parseFilters({ + ...filters, + websiteId, + timezone, + }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + session_data.string_value as x, + ${getDateSQL('session_data.created_at', unit, timezone)} t, + count(distinct session_data.session_id) y + from website_event + ${cohortQuery} + ${joinSessionQuery} + join session_data + on session_data.session_id = website_event.session_id + and session_data.website_id = website_event.website_id + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and session_data.data_key = {{propertyName}} + and session_data.data_type in (${DATA_TYPE.string}, ${DATA_TYPE.boolean}) + ${filterQuery} + ${pfSQL} + group by 1, 2 + order by 2 + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} + +async function clickhouseQuery( + websiteId: string, + propertyName: string, + filters: QueryFilters, + propertyFilters: PropertyFilter[] = [], +): Promise { + const { timezone = 'UTC', unit = 'day' } = filters; + const { rawQuery, getDateSQL, parseFilters, getPropertyFilterQuery } = clickhouse; + const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, timezone }); + const { sql: pfSQL, params: pfParams } = getPropertyFilterQuery(propertyFilters, 'session', timezone); + + return rawQuery( + ` + select + session_data.string_value as x, + ${getDateSQL('session_data.created_at', unit, timezone)} as t, + uniq(session_data.session_id) as y + from website_event + ${cohortQuery} + join session_data final + on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and session_data.data_key = {propertyName:String} + and session_data.data_type in (${DATA_TYPE.string}, ${DATA_TYPE.boolean}) + ${filterQuery} + ${pfSQL} + group by x, t + order by t + `, + { ...queryParams, propertyName, ...pfParams }, + FUNCTION_NAME, + ); +} diff --git a/src/queries/sql/sessions/getSessionDataValues.ts b/src/queries/sql/sessions/getSessionDataValues.ts index 5790141c5..1c7434768 100644 --- a/src/queries/sql/sessions/getSessionDataValues.ts +++ b/src/queries/sql/sessions/getSessionDataValues.ts @@ -1,4 +1,5 @@ import clickhouse from '@/lib/clickhouse'; +import { DATA_TYPE } from '@/lib/constants'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import type { QueryFilters } from '@/lib/types'; @@ -6,7 +7,7 @@ import type { QueryFilters } from '@/lib/types'; const FUNCTION_NAME = 'getSessionDataValues'; export async function getSessionDataValues( - ...args: [websiteId: string, filters: QueryFilters & { propertyName?: string }] + ...args: [websiteId: string, filters: QueryFilters & { propertyName?: string; dataType?: number }] ) { return runQuery({ [PRISMA]: () => relationalQuery(...args), @@ -16,14 +17,42 @@ export async function getSessionDataValues( async function relationalQuery( websiteId: string, - filters: QueryFilters & { propertyName?: string }, + filters: QueryFilters & { propertyName?: string; dataType?: number }, ) { const { rawQuery, parseFilters, getDateSQL } = prisma; + const { dataType } = filters; const { filterQuery, joinSessionQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId, }); + if (dataType === DATA_TYPE.array) { + return rawQuery( + ` + select + array_item.value as "value", + count(*) as "total" + from website_event + ${cohortQuery} + ${joinSessionQuery} + join session_data + on session_data.session_id = website_event.session_id + and session_data.website_id = website_event.website_id + cross join lateral jsonb_array_elements_text(coalesce(session_data.string_value, '[]')::jsonb) as array_item(value) + where website_event.website_id = {{websiteId::uuid}} + and website_event.created_at between {{startDate}} and {{endDate}} + and session_data.data_key = {{propertyName}} + and session_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + group by array_item.value + order by 2 desc + limit 500 + `, + queryParams, + FUNCTION_NAME, + ); + } + return rawQuery( ` select @@ -32,7 +61,7 @@ async function relationalQuery( when data_type = 4 then ${getDateSQL('date_value', 'hour')} else string_value end as "value", - count(distinct session_data.session_id) as "total" + count(*) as "total" from website_event ${cohortQuery} ${joinSessionQuery} @@ -42,10 +71,11 @@ async function relationalQuery( where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} and session_data.data_key = {{propertyName}} + ${dataType ? `and session_data.data_type = ${dataType}` : ''} ${filterQuery} group by value order by 2 desc - limit 100 + limit 500 `, queryParams, FUNCTION_NAME, @@ -54,18 +84,44 @@ async function relationalQuery( async function clickhouseQuery( websiteId: string, - filters: QueryFilters & { propertyName?: string }, + filters: QueryFilters & { propertyName?: string; dataType?: number }, ): Promise<{ propertyName: string; dataType: number; propertyValue: string; total: number }[]> { const { rawQuery, parseFilters } = clickhouse; + const { dataType } = filters; const { filterQuery, cohortQuery, queryParams } = parseFilters({ ...filters, websiteId }); + if (dataType === DATA_TYPE.array) { + return rawQuery( + ` + select + arrayJoin(JSONExtract(ifNull(session_data.string_value, '[]'), 'Array(String)')) as "value", + count() as "total" + from website_event + ${cohortQuery} + join session_data final + on session_data.session_id = website_event.session_id + and session_data.website_id = {websiteId:UUID} + where website_event.website_id = {websiteId:UUID} + and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} + and session_data.data_key = {propertyName:String} + and session_data.data_type = ${DATA_TYPE.array} + ${filterQuery} + group by value + order by 2 desc + limit 500 + `, + queryParams, + FUNCTION_NAME, + ); + } + return rawQuery( ` select multiIf(data_type = 2, replaceAll(string_value, '.0000', ''), data_type = 4, toString(date_trunc('hour', date_value)), string_value) as "value", - uniq(session_data.session_id) as "total" + count() as "total" from website_event ${cohortQuery} join session_data final @@ -74,10 +130,11 @@ async function clickhouseQuery( where website_event.website_id = {websiteId:UUID} and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64} and session_data.data_key = {propertyName:String} + ${dataType ? `and session_data.data_type = ${dataType}` : ''} ${filterQuery} group by value order by 2 desc - limit 100 + limit 500 `, queryParams, FUNCTION_NAME, diff --git a/src/tracker/index.js b/src/tracker/index.js index 85ad2ffea..521a1f717 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -37,6 +37,7 @@ const domain = config('domains') || ''; const credentials = config('fetch-credentials') || 'omit'; const perf = config('performance') === _true; + const autoPageview = config('auto-pageview') !== _false; const domains = domain.split(',').map(n => n.trim()); const host = @@ -90,7 +91,7 @@ currentRef = currentUrl; currentUrl = normalize(new URL(url, location.href).toString()); - if (currentUrl !== currentRef) { + if (currentUrl !== currentRef && autoPageview) { setTimeout(track, delayDuration); } }; @@ -197,7 +198,7 @@ const init = () => { if (!initialized) { initialized = true; - track(); + if (autoPageview) track(); handlePathChanges(); handleClicks(); if (perf) initPerformance();