Compare commits

...
Author SHA1 Message Date
Josh HawkinsandGitHub 9fec1c76b5 Update zod to 4 (#24791)
CI / AMD64 Build (push) Waiting to run
CI / AMD64 Smoke Test (push) Blocked by required conditions
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* fix races in ui settings import e2e tests

confirmImport clicked any button named "Import", so when the file parse was slow it hit the Import Settings button before the dialog opened and the page never reloaded. The click is now scoped to the dialog. The legacy layouts test also wrote naturalAspectLayout after the view had already read it, so it reloads the view after the write.

* update zod to 4.6.7

zod 4 types the input of z.coerce.number() as unknown, so the zone, camera wizard, and classification edit forms pass number to keep their field types. The ONVIF port error showed zod's built-in English text, which zod 4 rewords, so it now uses a translated message. New e2e tests cover zone inertia validation and camera wizard step 1 validation.
2026-10-25 20:44:39 -06:00
Josh HawkinsandGitHub 7d4b87946e Miscellaneous fixes (#24790)
* stagger the daily region grid rebuild across cameras

Every camera requested its region grid at exactly 02:00, so the requests queued up in the dispatcher and held up recording segment inserts behind them. Each camera now picks a random offset of up to an hour.

* only log ffmpeg crashes when restarting

* round preview skeleton corners to match the player
2026-10-25 18:13:00 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7738f022e7 Update openai requirement from ==3.35.* to ==3.36.* in /docker/main (#24784)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Updates the requirements on [openai](https://github.com/openai/openai-python) to permit the latest version.
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v3.35.0...v3.36.1)

---
updated-dependencies:
- dependency-name: openai
  dependency-version: 3.36.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:20 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ba6e3717f4 Update google-genai requirement (#24779)
Updates the requirements on [google-genai](https://github.com/googleapis/python-genai) to permit the latest version.

Updates `google-genai` to 2.32.0
- [Release notes](https://github.com/googleapis/python-genai/releases)
- [Changelog](https://github.com/googleapis/python-genai/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/python-genai/compare/v2.31.0...v2.32.0)

---
updated-dependencies:
- dependency-name: google-genai
  dependency-version: 2.32.0
  dependency-type: direct:production
  dependency-group: pydantic-genai
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:12 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
197ed252d2 Update onnxruntime requirement from ==1.30.* to ==1.31.* in /docker/main (#24781)
Updates the requirements on [onnxruntime](https://github.com/microsoft/onnxruntime) to permit the latest version.
- [Release notes](https://github.com/microsoft/onnxruntime/releases)
- [Changelog](https://github.com/microsoft/onnxruntime/blob/main/docs/ReleaseNotesWorkflow.md)
- [Commits](https://github.com/microsoft/onnxruntime/compare/v1.30.0...v1.31.0)

---
updated-dependencies:
- dependency-name: onnxruntime
  dependency-version: 1.31.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:01 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
14ddaf9df3 Bump tzlocal in /docker/main in the pip-main-minor-patch group (#24780)
Bumps the pip-main-minor-patch group in /docker/main with 1 update: [tzlocal](https://github.com/regebro/tzlocal).


Updates `tzlocal` from 5.4.4 to 5.4.5
- [Changelog](https://github.com/regebro/tzlocal/blob/master/CHANGES.txt)
- [Commits](https://github.com/regebro/tzlocal/compare/5.4.4...5.4.5)

---
updated-dependencies:
- dependency-name: tzlocal
  dependency-version: 5.4.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-main-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:12:21 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Josh HawkinsClaude Opus 5.5
113d499a61 Update fastapi requirement from ==0.153.* to ==0.159.* in /docker/main (#24783)
* Update fastapi requirement from ==0.153.* to ==0.159.* in /docker/main

Updates the requirements on [fastapi](https://github.com/fastapi/fastapi) to permit the latest version.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.153.0...0.159.1)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.159.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Move enum param hints to json_schema_extra for fastapi 0.159

FastAPI 0.159 no longer accepts extra keyword arguments on Path() and
Query(), so passing enum= raised a TypeError on import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 08:09:44 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ccb58bdff4 Bump actions/setup-python (#24782)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Bumps the actions group with 1 update in the / directory: [actions/setup-python](https://github.com/actions/setup-python).


Updates `actions/setup-python` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v7.0.0...v7.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:03:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
68acbe98b2 Bump the web-minor-patch group in /web with 8 updates (#24785)
Bumps the web-minor-patch group in /web with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [apexcharts](https://github.com/apexcharts/apexcharts.js) | `8.3.1` | `8.4.1` |
| [framer-motion](https://github.com/motiondivision/motion) | `14.4.0` | `14.6.0` |
| [i18next](https://github.com/i18next/i18next) | `26.5.3` | `26.5.5` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.60.0` | `1.61.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.1.0` | `17.1.1` |
| [virtua](https://github.com/inokawa/virtua) | `0.53.5` | `0.53.6` |
| [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) | `4.17.26` | `4.17.27` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.3.4` | `8.3.5` |


Updates `apexcharts` from 8.3.1 to 8.4.1
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Commits](https://github.com/apexcharts/apexcharts.js/compare/v8.3.1...v8.4.1)

Updates `framer-motion` from 14.4.0 to 14.6.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v14.4.0...v14.6.0)

Updates `i18next` from 26.5.3 to 26.5.5
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.5.3...v26.5.5)

Updates `lucide-react` from 1.60.0 to 1.61.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.61.0/packages/lucide-react)

Updates `react-i18next` from 17.1.0 to 17.1.1
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.1.0...v17.1.1)

Updates `virtua` from 0.53.5 to 0.53.6
- [Release notes](https://github.com/inokawa/virtua/releases)
- [Commits](https://github.com/inokawa/virtua/compare/0.53.5...0.53.6)

Updates `@types/lodash` from 4.17.26 to 4.17.27
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

Updates `vite` from 8.3.4 to 8.3.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.3.5/packages/vite)

---
updated-dependencies:
- dependency-name: apexcharts
  dependency-version: 8.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: framer-motion
  dependency-version: 14.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: i18next
  dependency-version: 26.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: lucide-react
  dependency-version: 1.61.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: virtua
  dependency-version: 0.53.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@types/lodash"
  dependency-version: 4.17.27
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: vite
  dependency-version: 8.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:03:32 -05:00
16 changed files with 295 additions and 173 deletions
+1 -1
View File
@@ -87,7 +87,7 @@ jobs:
with:
persist-credentials: false
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v7.0.0
uses: actions/setup-python@v7.1.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Install requirements
+5 -5
View File
@@ -4,7 +4,7 @@ click == 8.5.*
aiohttp == 3.14.*
starlette == 1.9.*
starlette-context == 0.5.*
fastapi[standard-no-fastapi-cloud-cli] == 0.153.*
fastapi[standard-no-fastapi-cloud-cli] == 0.159.*
uvicorn == 0.54.*
slowapi == 0.1.*
joserfc == 1.7.*
@@ -28,7 +28,7 @@ git+https://github.com/fbcotter/py3nvml#egg=py3nvml
tzdata == 2026.5
pyzmq == 27.2.*
ruamel.yaml == 0.19.*
tzlocal == 5.4.4
tzlocal == 5.4.5
requests == 2.34.*
types-requests == 2.33.*
norfair == 2.3.*
@@ -43,13 +43,13 @@ opencv-contrib-python == 4.11.0.*
scipy == 1.17.*
# OpenVino & ONNX
openvino == 2026.4.*
onnxruntime == 1.30.*
onnxruntime == 1.31.*
# Embeddings
transformers == 5.20.*
# Generative AI
google-genai == 2.31.*
google-genai == 2.32.*
ollama == 0.6.*
openai == 3.35.*
openai == 3.36.*
# push notifications
py-vapid == 1.9.6
pywebpush == 2.5.*
+1 -1
View File
@@ -1315,7 +1315,7 @@ def nvinfo():
dependencies=[Depends(require_role(["admin"]))],
)
async def logs(
service: str = Path(enum=["frigate", "nginx", "go2rtc"]),
service: str = Path(json_schema_extra={"enum": ["frigate", "nginx", "go2rtc"]}),
download: str | None = None,
stream: bool | None = False,
start: int | None = 0,
+3 -3
View File
@@ -337,7 +337,7 @@ async def get_snapshot_from_recording(
request: Request,
camera_name: str,
frame_time: float,
format: str = Path(enum=["png", "jpg"]),
format: str = Path(json_schema_extra={"enum": ["png", "jpg"]}),
height: int = None,
):
if camera_name not in request.app.frigate_config.cameras:
@@ -1061,7 +1061,7 @@ async def event_thumbnail(
max_cache_age: int = Query(
2592000, description="Max cache age in seconds. Default 30 days in seconds."
),
format: str = Query(default="ios", enum=["ios", "android"]),
format: str = Query(default="ios", json_schema_extra={"enum": ["ios", "android"]}),
):
thumbnail_bytes = None
event_complete = False
@@ -1858,7 +1858,7 @@ async def preview_mp4(
async def review_preview(
request: Request,
event_id: str,
format: str = Query(default="gif", enum=["gif", "mp4"]),
format: str = Query(default="gif", json_schema_extra={"enum": ["gif", "mp4"]}),
):
try:
review: ReviewSegment = ReviewSegment.get(ReviewSegment.id == event_id)
+6 -3
View File
@@ -2,10 +2,11 @@
import logging
import queue
import random
import threading
import time
from collections import deque
from datetime import UTC, datetime
from datetime import UTC, datetime, timedelta
from multiprocessing import Queue
from multiprocessing.synchronize import Event as MpEvent
from typing import Any
@@ -255,7 +256,9 @@ def process_frames(
region_grid: list[list[dict[str, Any]]],
exit_on_empty: bool = False,
):
next_region_update = get_tomorrow_at_time(2)
# cameras share one dispatcher, so stagger the daily grid rebuilds
region_update_offset = timedelta(seconds=random.randrange(3600))
next_region_update = get_tomorrow_at_time(2) + region_update_offset
config_subscriber = CameraConfigUpdateSubscriber(
None,
{camera_config.name: camera_config},
@@ -344,7 +347,7 @@ def process_frames(
if updated_grid:
region_grid = updated_grid
next_region_update = get_tomorrow_at_time(2)
next_region_update = get_tomorrow_at_time(2) + region_update_offset
try:
if exit_on_empty:
+6 -6
View File
@@ -474,10 +474,10 @@ class CameraWatchdog(threading.Thread):
if not self.capture_thread.is_alive():
self.detect_status.send("offline", now)
self.camera_fps.value = 0
self.logger.error(
f"Ffmpeg process crashed unexpectedly for {self.config.name}."
)
if can_restart:
self.logger.error(
f"Ffmpeg process crashed unexpectedly for {self.config.name}."
)
self.reset_capture_thread(terminate=False)
last_restart_time = now
elif self.camera_fps.value >= (self.config.detect.fps + 10):
@@ -498,10 +498,10 @@ class CameraWatchdog(threading.Thread):
elif now - self.capture_thread.current_frame.value > 20:
self.detect_status.send("offline", now)
self.camera_fps.value = 0
self.logger.info(
f"No frames received from {self.config.name} in 20 seconds. Exiting ffmpeg..."
)
if can_restart:
self.logger.info(
f"No frames received from {self.config.name} in 20 seconds. Exiting ffmpeg..."
)
self.reset_capture_thread()
last_restart_time = now
else:
@@ -0,0 +1,77 @@
/**
* Add-camera wizard Step 1 validation -- MEDIUM tier.
*
* Continue validates every field, so an invalid ONVIF port or a non-RTSP
* custom URL must show its translated message and keep the wizard on Step 1.
*/
import { test, expect } from "../../fixtures/frigate-test";
import type { Page } from "@playwright/test";
const PORT_ERROR = "ONVIF port must be a whole number from 1 to 65535";
async function openWizard(page: Page) {
await page.getByRole("button", { name: /Add New Camera/i }).click();
const dialog = page.getByRole("dialog");
await expect(dialog).toBeVisible();
await dialog.getByPlaceholder(/front_door/i).fill("step1_camera");
return dialog;
}
test.describe("Camera wizard step 1 validation @medium @mobile", () => {
test.beforeEach(async ({ frigateApp }) => {
// not in the default mock; unmocked it 500s and trips the error collector
await frigateApp.page.route("**/api/config/raw_paths", (route) =>
route.fulfill({ json: {} }),
);
await frigateApp.page.route("**/api/onvif/probe**", (route) =>
route.fulfill({ json: { success: false } }),
);
await frigateApp.goto("/settings?page=cameraManagement");
await expect(
frigateApp.page.getByRole("heading", { name: /Manage Cameras/i }),
).toBeVisible();
});
test("an invalid ONVIF port blocks Continue with a translated message", async ({
frigateApp,
}) => {
const dialog = await openWizard(frigateApp.page);
await dialog.getByPlaceholder("192.168.1.100").fill("192.168.1.100");
const port = dialog.getByPlaceholder("80", { exact: true });
const next = dialog.getByRole("button", { name: /^Continue$/i });
for (const value of ["abc", "0", "70000", "80.5"]) {
await port.fill(value);
await next.click();
await expect(dialog.getByText(PORT_ERROR)).toBeVisible();
await expect(port).toBeVisible();
}
await port.fill("8080");
await next.click();
await expect(port).toBeHidden();
await expect(dialog.getByText(PORT_ERROR)).toBeHidden();
});
test("a custom URL must use RTSP", async ({ frigateApp }) => {
const dialog = await openWizard(frigateApp.page);
await dialog.getByText("Manual selection", { exact: true }).click();
await dialog.getByRole("combobox").click();
await frigateApp.page.getByRole("option", { name: "Other" }).click();
const url = dialog.getByPlaceholder(
"rtsp://username:password@host:port/path",
);
const next = dialog.getByRole("button", { name: /^Continue$/i });
await url.fill("http://192.168.1.100/stream");
await next.click();
await expect(
dialog.getByText(/Custom URLs must begin with "rtsp:\/\/"/),
).toBeVisible();
await url.fill("rtsp://192.168.1.100/stream");
await next.click();
await expect(url).toBeHidden();
});
});
@@ -121,9 +121,14 @@ async function confirmImport(page: Page) {
// route change, so #pageRoot is already present and waiting for it
// alone can race the navigation. Wait for the "load" event first so
// the evaluate() calls below run against the post-reload document.
// scoped to the dialog: until it opens, a page-wide "Import" match is the
// Import Settings button, which only reopens the file chooser
await Promise.all([
page.waitForEvent("load"),
page.getByRole("button", { name: "Import" }).click(),
page
.getByRole("dialog")
.getByRole("button", { name: "Import", exact: true })
.click(),
]);
await page.waitForSelector("#pageRoot");
}
@@ -270,6 +275,9 @@ test.describe("UI settings import/export @medium", () => {
// naturalAspectLayout preference must not override that.
await frigateApp.goto("/settings?page=uiSettings");
await writeIdb(frigateApp.page, { "naturalAspectLayout:admin": true });
// the view reads the setting once on mount, so load it again after the
// write
await frigateApp.goto("/settings?page=uiSettings");
await chooseImportFile(
frigateApp.page,
+33
View File
@@ -248,4 +248,37 @@ test.describe("zone rename and delete @medium @mobile", () => {
},
});
});
test("inertia below 1 blocks saving and a valid value saves as a number", async ({
frigateApp,
}) => {
const requests = await installRoutes(frigateApp.page);
await frigateApp.goto(SETTINGS_URL);
await openZoneAction(frigateApp.page, frigateApp.isMobile, "Edit");
const inertia = frigateApp.page.getByRole("textbox", {
name: "Inertia",
exact: true,
});
const save = frigateApp.page.getByRole("button", { name: "Save" });
await inertia.fill("0");
await expect(
frigateApp.page.getByText("Inertia must be above 0."),
).toBeVisible();
await expect(save).toBeDisabled();
await inertia.fill("5");
await expect(
frigateApp.page.getByText("Inertia must be above 0."),
).toBeHidden();
await save.click();
await expect.poll(() => requests.length).toBe(1);
expect(requests[0].body).toMatchObject({
config_data: {
cameras: { front_door: { zones: { driveway: { inertia: 5 } } } },
},
});
});
});
+120 -130
View File
@@ -37,7 +37,7 @@
"@rjsf/shadcn": "^6.10.1",
"@rjsf/utils": "^6.10.1",
"@rjsf/validator-ajv8": "^6.10.1",
"apexcharts": "^8.3.1",
"apexcharts": "^8.4.1",
"axios": "^1.20.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -45,15 +45,15 @@
"copy-to-clipboard": "^4.0.2",
"date-fns": "^4.4.0",
"date-fns-tz": "^3.2.0",
"framer-motion": "^14.4.0",
"framer-motion": "^14.6.0",
"hls.js": "^1.7.3",
"i18next": "^26.5.3",
"i18next": "^26.5.5",
"i18next-http-backend": "^4.0.4",
"idb-keyval": "^6.3.0",
"js-yaml": "^5.5.0",
"konva": "^10.9.0",
"lodash": "^4.18.1",
"lucide-react": "^1.60.0",
"lucide-react": "^1.61.0",
"monaco-yaml": "^5.5.1",
"next-themes": "^0.4.6",
"nosleep.js": "^0.12.0",
@@ -65,7 +65,7 @@
"react-dropzone": "^20.1.4",
"react-grid-layout": "^2.3.0",
"react-hook-form": "^7.90.0",
"react-i18next": "^17.1.0",
"react-i18next": "^17.1.1",
"react-icons": "^5.7.0",
"react-konva": "^19.3.2",
"react-markdown": "^10.1.0",
@@ -81,15 +81,15 @@
"tailwindcss-animate": "^1.0.7",
"use-long-press": "^3.3.0",
"vaul": "^1.1.2",
"virtua": "^0.53.5",
"virtua": "^0.53.6",
"vite-plugin-monaco-editor": "^1.1.0",
"zod": "^3.25.76"
"zod": "^4.6.7"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.64.1",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.26",
"@types/lodash": "^4.17.27",
"@types/node": "^26.6.5",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
@@ -111,7 +111,7 @@
"tailwindcss": "^3.4.19",
"typescript": "^6.0.3",
"typescript-eslint": "^8.72.0",
"vite": "^8.3.4"
"vite": "^8.3.5"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -1695,9 +1695,9 @@
}
},
"node_modules/@oxc-project/types": {
"version": "0.153.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz",
"integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==",
"version": "0.155.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz",
"integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==",
"dev": true,
"license": "MIT",
"funding": {
@@ -3022,9 +3022,9 @@
}
},
"node_modules/@rolldown/binding-android-arm-eabi": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz",
"integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz",
"integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==",
"cpu": [
"arm"
],
@@ -3039,9 +3039,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz",
"integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz",
"integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==",
"cpu": [
"arm64"
],
@@ -3056,9 +3056,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz",
"integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz",
"integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==",
"cpu": [
"arm64"
],
@@ -3073,9 +3073,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz",
"integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz",
"integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==",
"cpu": [
"x64"
],
@@ -3090,9 +3090,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz",
"integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz",
"integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==",
"cpu": [
"x64"
],
@@ -3107,9 +3107,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz",
"integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz",
"integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==",
"cpu": [
"arm"
],
@@ -3124,9 +3124,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz",
"integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz",
"integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==",
"cpu": [
"arm64"
],
@@ -3141,9 +3141,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz",
"integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz",
"integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==",
"cpu": [
"arm64"
],
@@ -3158,9 +3158,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz",
"integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz",
"integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==",
"cpu": [
"ppc64"
],
@@ -3175,9 +3175,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz",
"integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz",
"integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==",
"cpu": [
"s390x"
],
@@ -3192,9 +3192,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz",
"integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz",
"integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==",
"cpu": [
"x64"
],
@@ -3209,9 +3209,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz",
"integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz",
"integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==",
"cpu": [
"x64"
],
@@ -3226,9 +3226,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz",
"integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz",
"integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==",
"cpu": [
"arm64"
],
@@ -3243,9 +3243,9 @@
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz",
"integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz",
"integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==",
"cpu": [
"arm64"
],
@@ -3260,9 +3260,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz",
"integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz",
"integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==",
"cpu": [
"x64"
],
@@ -3589,9 +3589,9 @@
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.26",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.26.tgz",
"integrity": "sha512-48NWfiY6oNcKOh47Z4h+sIvwcQR91h6KPhaYKgeMIrkT2jV82Gy90SErj60vW8jQbeMSOSbhIv3bZ7JoqPPVhA==",
"version": "4.17.27",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.27.tgz",
"integrity": "sha512-VenMRv/eKNrspX9v3H4dbmjsrnCOYdYBG3kxXKk3dG6X+urBGcj2Prww3xw1U5K4FV/mE4h5GbWd0szEKf+9ew==",
"dev": true,
"license": "MIT"
},
@@ -4061,18 +4061,18 @@
}
},
"node_modules/apex-commons": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/apex-commons/-/apex-commons-0.8.1.tgz",
"integrity": "sha512-F7fqJVh0smeTu1d86uuRSNNZvaM/l11GNQMbu6oAiSvuXp+K8KCufg0oZTy2VQBEEipRLAdFqkHnphlVpTG0Gw==",
"license": "SEE LICENSE IN LICENSE"
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/apex-commons/-/apex-commons-0.8.3.tgz",
"integrity": "sha512-WdU5lblyL1ByI/nkFOJkSgJYenCsHmay0P3UIcnSeUiCyF1b30SvPSZLbyxOCUOry8IlL7M0/3GvsGbZTMm8FA==",
"license": "SEE LICENSE IN LICENSE.md"
},
"node_modules/apexcharts": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-8.3.1.tgz",
"integrity": "sha512-Z0LX1rPyXBe85082t9EqUWzikOdLy3Z184cvL+4uYS7J4kyLAzK50JBtAGKH5OU8Y6EOPqiH8BqjxjMIBF2+gw==",
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-8.4.1.tgz",
"integrity": "sha512-29IbZ1rn3NRkDvete5EzZXy6yDSW7mjNXkytLpvaYHk0XbfsR+FvC7U78L3wMvJa699NBmix2z6r3Qm5YDvw0A==",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"apex-commons": "^0.8.0"
"apex-commons": "^0.8.3"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
@@ -5097,16 +5097,6 @@
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/eslint-plugin-react-hooks/node_modules/zod": {
"version": "4.6.5",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
"integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/eslint-plugin-react-hooks/node_modules/zod-validation-error": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
@@ -5592,13 +5582,13 @@
}
},
"node_modules/framer-motion": {
"version": "14.4.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-14.4.0.tgz",
"integrity": "sha512-HtO1fxord2rnXYRyr1laG4uY7+OtgwDc9Szcg1wlMq/LF7BO3/S7a+KEo691U7pSi+i0ueRuRqaD1UaLEmZHuQ==",
"version": "14.6.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-14.6.0.tgz",
"integrity": "sha512-MzBgZxGgoHPfSLEXmo4o5XlZvb+nVRFdHtGjVhm6LMIEJKTt/8hNO023euL5mYyzc8llV/hQTfjnN68tNRHalw==",
"license": "MIT",
"dependencies": {
"motion-dom": "14.4.0",
"motion-utils": "14.1.1",
"motion-dom": "14.6.0",
"motion-utils": "14.6.0",
"tslib": "^2.4.0"
},
"peerDependencies": {
@@ -6001,9 +5991,9 @@
}
},
"node_modules/i18next": {
"version": "26.5.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.5.3.tgz",
"integrity": "sha512-6pRwOwJ6lBCBB66fqNZaSoUmvsALHMord7FL6GsDhubT1CrPabTMEJIqddm0nn2YEbKofdI/3VAtGrQPuztY1Q==",
"version": "26.5.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.5.5.tgz",
"integrity": "sha512-txdaNOlnZCdiTMSlEzl5hUJU8TC9R4J/RCR1G7XrDPbWT2t3mR142QPz84ZuZeXDt3yq+9zmsdPiakxYtmp3fw==",
"funding": [
{
"type": "individual",
@@ -6988,9 +6978,9 @@
}
},
"node_modules/lucide-react": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.60.0.tgz",
"integrity": "sha512-UqxOW0FgAfDyb9VmjKb6/BkOzW6yfhf/QNboKtS2NDsscnNRW2CDzlyhbMKBQ1ontmcxuIDqHJ2AVgFR3NI+GA==",
"version": "1.61.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.61.0.tgz",
"integrity": "sha512-v2SQPPPNjnr+BlhL9Spuzmo5yR+hLkftfuE4E3jaxdNPgSH0hJKPcLJBP7yAta87jQNPsSERS59PJjCJ/CorBA==",
"license": "ISC",
"peerDependencies": {
"@types/react": "*",
@@ -8065,18 +8055,18 @@
}
},
"node_modules/motion-dom": {
"version": "14.4.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-14.4.0.tgz",
"integrity": "sha512-1q8RyHSdr5COpzrv3JgJ9XRjOO88ZN9CwflpkGgyO/SR/SNRP/dD6EU8SEo092kcKY34IzHC5diJPKrQRMA8lQ==",
"version": "14.6.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-14.6.0.tgz",
"integrity": "sha512-lIojTl9aYSPIkeOOSzBliy1nNvpdO3JtVzW2WgTXQlOP4ZMuJhtWO3fP7OD4TVFwlRucdvxlDSMkL+fEQnQ52A==",
"license": "MIT",
"dependencies": {
"motion-utils": "14.1.1"
"motion-utils": "14.6.0"
}
},
"node_modules/motion-utils": {
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-14.1.1.tgz",
"integrity": "sha512-3VvN5Uvf8B6qG+OfOui6Nht5EWp+vLuU3IqcAj7ItZGKqtmTjCebl5sGZF7/08gEHRnEl1AP/fIwbcEyVrcQGQ==",
"version": "14.6.0",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-14.6.0.tgz",
"integrity": "sha512-bZJo2AmQ2aOFkaato6VXrTbkPG0XhMzivWUWSaI59pxyllj8QMQUFZ84MYRQnPkK+7dr4KldyJwF2+RM0sdq/w==",
"license": "MIT"
},
"node_modules/ms": {
@@ -9069,9 +9059,9 @@
}
},
"node_modules/react-i18next": {
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.1.0.tgz",
"integrity": "sha512-4VouOnTDyvhvqXx6WZ+s3/cgSiaLutILdYkO3P1Ms+4qcKR7At+JP4Vi7IeHkVLyVV+DmN1l23Pn73UcwSGGPA==",
"version": "17.1.1",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.1.1.tgz",
"integrity": "sha512-Q76xpzxrZNcqhB7M31Ns7isulGOlmhURqRsJOGlYgJJCyoy1pMq6tRl8KQycGNNY1vPaxbIdrogrqY9nkb+SEA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.7",
@@ -9487,13 +9477,13 @@
}
},
"node_modules/rolldown": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz",
"integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==",
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz",
"integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.153.0",
"@oxc-project/types": "=0.155.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -9503,21 +9493,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
"@rolldown/binding-android-arm-eabi": "1.2.13",
"@rolldown/binding-android-arm64": "1.2.13",
"@rolldown/binding-darwin-arm64": "1.2.13",
"@rolldown/binding-darwin-x64": "1.2.13",
"@rolldown/binding-freebsd-x64": "1.2.13",
"@rolldown/binding-linux-arm-gnueabihf": "1.2.13",
"@rolldown/binding-linux-arm64-gnu": "1.2.13",
"@rolldown/binding-linux-arm64-musl": "1.2.13",
"@rolldown/binding-linux-ppc64-gnu": "1.2.13",
"@rolldown/binding-linux-s390x-gnu": "1.2.13",
"@rolldown/binding-linux-x64-gnu": "1.2.13",
"@rolldown/binding-linux-x64-musl": "1.2.13",
"@rolldown/binding-openharmony-arm64": "1.2.13",
"@rolldown/binding-win32-arm64-msvc": "1.2.13",
"@rolldown/binding-win32-x64-msvc": "1.2.13"
"@rolldown/binding-android-arm-eabi": "1.2.15",
"@rolldown/binding-android-arm64": "1.2.15",
"@rolldown/binding-darwin-arm64": "1.2.15",
"@rolldown/binding-darwin-x64": "1.2.15",
"@rolldown/binding-freebsd-x64": "1.2.15",
"@rolldown/binding-linux-arm-gnueabihf": "1.2.15",
"@rolldown/binding-linux-arm64-gnu": "1.2.15",
"@rolldown/binding-linux-arm64-musl": "1.2.15",
"@rolldown/binding-linux-ppc64-gnu": "1.2.15",
"@rolldown/binding-linux-s390x-gnu": "1.2.15",
"@rolldown/binding-linux-x64-gnu": "1.2.15",
"@rolldown/binding-linux-x64-musl": "1.2.15",
"@rolldown/binding-openharmony-arm64": "1.2.15",
"@rolldown/binding-win32-arm64-msvc": "1.2.15",
"@rolldown/binding-win32-x64-msvc": "1.2.15"
}
},
"node_modules/run-async": {
@@ -10374,9 +10364,9 @@
}
},
"node_modules/virtua": {
"version": "0.53.5",
"resolved": "https://registry.npmjs.org/virtua/-/virtua-0.53.5.tgz",
"integrity": "sha512-hhtrEli6LkMzKXhqhuStnaU5DECVLjxwr/FbrGcnkId2gyKQJ/5E6LE/T2F4OzyghEOsOCl/g+0DyxJUmkah8Q==",
"version": "0.53.6",
"resolved": "https://registry.npmjs.org/virtua/-/virtua-0.53.6.tgz",
"integrity": "sha512-/vQtSFNDFcp3Yz4klbpe8Z88eQeThSw49cFlgJQdsqh3SUnRlW4jLi6ZYt4YzdwerYGlP6KCgAOXNVO+PmUg7w==",
"license": "MIT",
"peerDependencies": {
"@angular/common": ">=20.0.0",
@@ -10412,16 +10402,16 @@
}
},
"node_modules/vite": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz",
"integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==",
"version": "8.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz",
"integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.33.0",
"picomatch": "^4.0.7",
"postcss": "^8.5.29",
"rolldown": "~1.2.12",
"postcss": "^8.5.30",
"rolldown": "~1.2.14",
"tinyglobby": "^0.2.17"
},
"bin": {
@@ -10438,7 +10428,7 @@
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
"@vitejs/devtools": "^0.7.1",
"@vitejs/devtools": "^0.7.1 || ^0.8.0",
"esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
@@ -10637,9 +10627,9 @@
}
},
"node_modules/zod": {
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"version": "4.6.7",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz",
"integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
+9 -9
View File
@@ -49,7 +49,7 @@
"@rjsf/shadcn": "^6.10.1",
"@rjsf/utils": "^6.10.1",
"@rjsf/validator-ajv8": "^6.10.1",
"apexcharts": "^8.3.1",
"apexcharts": "^8.4.1",
"axios": "^1.20.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -57,15 +57,15 @@
"copy-to-clipboard": "^4.0.2",
"date-fns": "^4.4.0",
"date-fns-tz": "^3.2.0",
"framer-motion": "^14.4.0",
"framer-motion": "^14.6.0",
"hls.js": "^1.7.3",
"i18next": "^26.5.3",
"i18next": "^26.5.5",
"i18next-http-backend": "^4.0.4",
"idb-keyval": "^6.3.0",
"js-yaml": "^5.5.0",
"konva": "^10.9.0",
"lodash": "^4.18.1",
"lucide-react": "^1.60.0",
"lucide-react": "^1.61.0",
"monaco-yaml": "^5.5.1",
"next-themes": "^0.4.6",
"nosleep.js": "^0.12.0",
@@ -77,7 +77,7 @@
"react-dropzone": "^20.1.4",
"react-grid-layout": "^2.3.0",
"react-hook-form": "^7.90.0",
"react-i18next": "^17.1.0",
"react-i18next": "^17.1.1",
"react-icons": "^5.7.0",
"react-konva": "^19.3.2",
"react-markdown": "^10.1.0",
@@ -93,15 +93,15 @@
"tailwindcss-animate": "^1.0.7",
"use-long-press": "^3.3.0",
"vaul": "^1.1.2",
"virtua": "^0.53.5",
"virtua": "^0.53.6",
"vite-plugin-monaco-editor": "^1.1.0",
"zod": "^3.25.76"
"zod": "^4.6.7"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.64.1",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.26",
"@types/lodash": "^4.17.27",
"@types/node": "^26.6.5",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
@@ -123,7 +123,7 @@
"tailwindcss": "^3.4.19",
"typescript": "^6.0.3",
"typescript-eslint": "^8.72.0",
"vite": "^8.3.4"
"vite": "^8.3.5"
},
"overrides": {
"@radix-ui/react-compose-refs": "1.1.2",
+2 -1
View File
@@ -367,7 +367,8 @@
"nameLength": "Camera name must be 64 characters or less",
"invalidCharacters": "Camera name contains invalid characters",
"nameExists": "Camera name already exists",
"customUrlRtspRequired": "Custom URLs must begin with \"rtsp://\" or \"rtsps://\". Manual configuration is required for non-RTSP camera streams."
"customUrlRtspRequired": "Custom URLs must begin with \"rtsp://\" or \"rtsps://\". Manual configuration is required for non-RTSP camera streams.",
"onvifPortInvalid": "ONVIF port must be a whole number from 1 to 65535"
}
},
"step2": {
@@ -114,7 +114,7 @@ export default function ClassificationModelEditDialog({
const sharedFields = {
enabled: z.boolean(),
saveAttempts: z.coerce
.number({ message: t("edit.errors.saveAttemptsInvalid") })
.number<number>({ message: t("edit.errors.saveAttemptsInvalid") })
.int(t("edit.errors.saveAttemptsInvalid"))
.min(0, t("edit.errors.saveAttemptsInvalid")),
};
@@ -136,7 +136,7 @@ export default function ClassificationModelEditDialog({
(val) =>
val === "" || val === null || val === undefined ? undefined : val,
z.coerce
.number({ message: t("edit.errors.intervalInvalid") })
.number<number>({ message: t("edit.errors.intervalInvalid") })
.int(t("edit.errors.intervalInvalid"))
.positive(t("edit.errors.intervalInvalid"))
.optional(),
@@ -171,7 +171,6 @@ export default function ClassificationModelEditDialog({
resolver: zodResolver(
formSchema as z.ZodType<
ObjectFormData | StateFormData,
z.ZodTypeDef,
ObjectFormData | StateFormData
>,
),
+6 -2
View File
@@ -332,7 +332,9 @@ function PreviewVideoPlayer({
{t("noPreviewFoundFor", { cameraName: cameraName })}
</div>
)}
{firstLoad && <Skeleton className="absolute aspect-video size-full" />}
{firstLoad && (
<Skeleton className="absolute aspect-video size-full rounded-lg md:rounded-2xl" />
)}
</div>
);
}
@@ -555,7 +557,9 @@ function PreviewFramesPlayer({
{t("noPreviewFoundFor", { cameraName: cameraName })}
</div>
)}
{firstLoad && <Skeleton className="absolute aspect-video size-full" />}
{firstLoad && (
<Skeleton className="absolute aspect-video size-full rounded-lg md:rounded-2xl" />
)}
</div>
);
}
+7 -7
View File
@@ -200,13 +200,13 @@ export default function ZoneEditPane({
),
enabled: z.boolean().default(true),
inertia: z.coerce
.number()
.number<number>()
.min(1, {
message: t("masksAndZones.form.inertia.error.mustBeAboveZero"),
})
.or(z.literal("")),
loitering_time: z.coerce
.number()
.number<number>()
.min(0, {
message: t(
"masksAndZones.form.loiteringTime.error.mustBeGreaterOrEqualZero",
@@ -222,35 +222,35 @@ export default function ZoneEditPane({
review_detections: z.boolean().default(false).optional(),
speedEstimation: z.boolean().default(false),
lineA: z.coerce
.number()
.number<number>()
.min(0.1, {
message: t("masksAndZones.form.distance.error.text"),
})
.optional()
.or(z.literal("")),
lineB: z.coerce
.number()
.number<number>()
.min(0.1, {
message: t("masksAndZones.form.distance.error.text"),
})
.optional()
.or(z.literal("")),
lineC: z.coerce
.number()
.number<number>()
.min(0.1, {
message: t("masksAndZones.form.distance.error.text"),
})
.optional()
.or(z.literal("")),
lineD: z.coerce
.number()
.number<number>()
.min(0.1, {
message: t("masksAndZones.form.distance.error.text"),
})
.optional()
.or(z.literal("")),
speed_threshold: z.coerce
.number()
.number<number>()
.min(0.1, {
message: t("masksAndZones.form.speed.error.mustBeGreaterOrEqualTo"),
})
@@ -81,7 +81,14 @@ export default function Step1NameCamera({
username: z.string().optional(),
password: z.string().optional(),
brandTemplate: z.enum(CAMERA_BRAND_VALUES).optional(),
onvifPort: z.coerce.number().int().min(1).max(65535).optional(),
onvifPort: z.coerce
.number<number>({
message: t("cameraWizard.step1.errors.onvifPortInvalid"),
})
.int(t("cameraWizard.step1.errors.onvifPortInvalid"))
.min(1, t("cameraWizard.step1.errors.onvifPortInvalid"))
.max(65535, t("cameraWizard.step1.errors.onvifPortInvalid"))
.optional(),
useDigestAuth: z.boolean().optional(),
customUrl: z
.string()