Compare commits

..
Author SHA1 Message Date
Josh HawkinsandGitHub 33c55649a4 report custom go2rtc and ffmpeg builds in analytics (#24928)
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
Users can swap in their own go2rtc binary at /config/go2rtc or point ffmpeg.path at a custom build, and either can explain stream behavior that looks like a Frigate regression. The install section now reports a custom_go2rtc boolean and an ffmpeg enum (default, bundled, custom) for the configured global path, so no version strings or path text leave the install.
2026-11-09 14:05:16 -07:00
Josh HawkinsandGitHub c88434dc29 Write migrated config atomically (#24926)
* write migrated config atomically

Config migration rewrote config.yml in place with open("w") after each step, so nginx's get_nginx_settings.py, which starts alongside frigate, could read an empty file, get None from yaml.load, and crash on config.get. Each step now writes to a temp file with the original mode and os.replace's it into place.

* keep config owner and handle file bind mounts in migration writes

os.replace failed with EBUSY when config.yml was a file bind mount, as in the documented --validate-config command, and the replaced file lost its original owner when Frigate ran as root. The write now copies in place on EBUSY and restores the original owner when permitted. Tests cover a failed dump leaving the original config and the bind-mount fallback.

* follow config symlinks in migration writes
2026-11-09 13:56:34 -07:00
Josh HawkinsandGitHub e7256d58a1 strip nginx user directive when not running as root (#24925)
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
2026-11-09 12:41:19 -06:00
b2a7e992c9 Request FP16 TensorRT engine for ONNX detector with device Tensorrt (#24923)
* Request FP16 TensorRT engine for ONNX detector with device Tensorrt

get_ort_providers only enables trt_fp16_enable when requires_fp16 is
passed, and the ONNX detector never passed it, so device: Tensorrt
always built an FP32 engine. USE_FP16=False still disables FP16.

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

* Make TensorRT FP16 opt-in via USE_FP16 only

Drop the unused requires_fp16 parameter from get_ort_providers and decide
trt_fp16_enable from the USE_FP16 environment variable alone, defaulting
to false. Revert the ONNX detector change and document USE_FP16=true for
device: Tensorrt.

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

* Drop the TensorRT docs line

The stock image ships only the TensorRT runtime, not the builder
libraries needed to create engines, so the instructions were misleading.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 09:46:25 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
11f4dd194c Update google-genai requirement (#24920)
Updates the requirements on [google-genai](https://github.com/googleapis/python-genai) to permit the latest version.

Updates `google-genai` to 3.0.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.34.0...v3.0.0)

---
updated-dependencies:
- dependency-name: google-genai
  dependency-version: 3.0.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-11-09 08:25:39 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0e7da1bee4 Bump the web-minor-patch group in /web with 5 updates (#24922)
Bumps the web-minor-patch group in /web with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [framer-motion](https://github.com/motiondivision/motion) | `14.9.1` | `14.10.0` |
| [i18next](https://github.com/i18next/i18next) | `26.7.1` | `26.7.2` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.69.0` | `1.70.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.1.12` | `17.1.13` |
| [@playwright/test](https://github.com/microsoft/playwright) | `1.64.1` | `1.65.0` |


Updates `framer-motion` from 14.9.1 to 14.10.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v14.9.1...v14.10.0)

Updates `i18next` from 26.7.1 to 26.7.2
- [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.7.1...v26.7.2)

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

Updates `react-i18next` from 17.1.12 to 17.1.13
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.1.12...v17.1.13)

Updates `@playwright/test` from 1.64.1 to 1.65.0
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.64.1...v1.65.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 14.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: i18next
  dependency-version: 26.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: lucide-react
  dependency-version: 1.70.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.1.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@playwright/test"
  dependency-version: 1.65.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  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-11-09 08:25:23 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
14870f5237 Bump ruff in /docker/main in the pip-main-minor-patch group (#24921)
Bumps the pip-main-minor-patch group in /docker/main with 1 update: [ruff](https://github.com/astral-sh/ruff).


Updates `ruff` from 0.17.3 to 0.17.4
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.17.3...0.17.4)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.17.4
  dependency-type: direct:development
  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-11-09 08:25:17 -06:00
14 changed files with 234 additions and 62 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ onnxruntime == 1.31.*
# Embeddings
transformers == 5.22.*
# Generative AI
google-genai == 2.34.*
google-genai == 3.0.*
ollama == 0.6.*
openai == 3.46.*
# push notifications
@@ -80,6 +80,11 @@ cp -r /usr/local/nginx/conf/. /tmp/nginx/conf/
set_worker_processes
# A non-root master ignores `user` and warns on every start
if [[ "$runs_as_root" -eq 0 ]]; then
sed -i '/^user root;$/d' /tmp/nginx/conf/nginx.conf
fi
# TLS certs: user-mounted certs at /etc/letsencrypt/live/frigate (documented
# contract) always win; otherwise fall back to a self-signed cert persisted in
# /config/tls, which stays writable under a read-only root filesystem.
@@ -2,7 +2,7 @@
# file, all other path directives follow --prefix and must stay absolute.
daemon off;
# ignored by a non-root master; keeps workers root under FRIGATE_RUN_AS_ROOT
# keeps workers root under FRIGATE_RUN_AS_ROOT; the run script strips it otherwise
user root;
worker_processes auto;
+23 -1
View File
@@ -683,6 +683,15 @@
"title": "FeaturesSection",
"type": "object"
},
"FfmpegSource": {
"enum": [
"default",
"bundled",
"custom"
],
"title": "FfmpegSource",
"type": "string"
},
"FpsBucket": {
"enum": [
"le_5",
@@ -1017,6 +1026,17 @@
"description": "CPU architecture",
"x-public": true
},
"custom_go2rtc": {
"description": "Whether an executable /config/go2rtc build exists",
"title": "Custom Go2Rtc",
"type": "boolean",
"x-public": true
},
"ffmpeg": {
"$ref": "#/$defs/FfmpegSource",
"description": "Configured global ffmpeg.path: the default build, another bundled version, or a custom path",
"x-public": true
},
"image_variant": {
"$ref": "#/$defs/ImageVariant",
"description": "Published image the install runs",
@@ -1054,7 +1074,9 @@
"install_type",
"arch",
"kernel",
"run_as_root"
"run_as_root",
"custom_go2rtc",
"ffmpeg"
],
"title": "InstallSection",
"type": "object"
+22 -1
View File
@@ -6,7 +6,15 @@ import re
from frigate.analytics.collectors.common import closed
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import Arch, ImageVariant, InstallSection, InstallType
from frigate.analytics.schema import (
Arch,
FfmpegSource,
ImageVariant,
InstallSection,
InstallType,
)
from frigate.const import CONFIG_DIR, DEFAULT_FFMPEG_VERSION, INCLUDED_FFMPEG_VERSIONS
from frigate.util.config import is_valid_ffmpeg_path
from frigate.version import VERSION
KERNEL_PATTERN = re.compile(r"^(\d{1,3})\.(\d{1,3})")
@@ -54,6 +62,17 @@ def kernel(release: str) -> str:
return f"{match.group(1)}.{match.group(2)}" if match else "unknown"
def ffmpeg_source(path: str) -> FfmpegSource:
"""Classify the configured ffmpeg.path, applying resolve_ffmpeg_path's alias fallbacks."""
if path.startswith("/") and is_valid_ffmpeg_path(path):
return FfmpegSource.custom
if path != DEFAULT_FFMPEG_VERSION and path in INCLUDED_FFMPEG_VERSIONS:
return FfmpegSource.bundled
return FfmpegSource.default
def collect(ctx: ReportContext) -> InstallSection:
"""Describe the Frigate version, image, install method, and platform."""
return InstallSection(
@@ -63,4 +82,6 @@ def collect(ctx: ReportContext) -> InstallSection:
arch=arch(platform.machine()),
kernel=kernel(platform.release()),
run_as_root=os.geteuid() == 0,
custom_go2rtc=os.access(os.path.join(CONFIG_DIR, "go2rtc"), os.X_OK),
ffmpeg=ffmpeg_source(ctx.config.ffmpeg.path),
)
+10
View File
@@ -47,6 +47,12 @@ class Arch(StrEnum):
other = "other"
class FfmpegSource(StrEnum):
default = "default"
bundled = "bundled"
custom = "custom"
class GpuVendor(StrEnum):
intel = "intel"
amd = "amd"
@@ -201,6 +207,10 @@ class InstallSection(AnalyticsModel):
"Host kernel as major.minor", pattern=r"^(\d{1,3}\.\d{1,3}|unknown)$"
)
run_as_root: bool = metric("Whether the main process runs as root")
custom_go2rtc: bool = metric("Whether an executable /config/go2rtc build exists")
ffmpeg: FfmpegSource = metric(
"Configured global ffmpeg.path: the default build, another bundled version, or a custom path"
)
class GpuInfo(AnalyticsModel):
@@ -12,6 +12,7 @@ from frigate.analytics.collectors.common import closed, histogram, rate
from frigate.analytics.schema import (
Arch,
DecodeFamily,
FfmpegSource,
GpuVendor,
HardwareKey,
ImageVariant,
@@ -56,6 +57,36 @@ class TestInstallCollector(unittest.TestCase):
self.assertEqual(section.arch, Arch.aarch64)
self.assertEqual(section.kernel, "6.8")
self.assertFalse(section.run_as_root)
self.assertEqual(section.ffmpeg, FfmpegSource.default)
def test_ffmpeg_source_follows_path_resolution(self):
with (
patch.object(install, "DEFAULT_FFMPEG_VERSION", "8.0"),
patch.object(install, "INCLUDED_FFMPEG_VERSIONS", ["8.0", "7.0"]),
):
self.assertEqual(install.ffmpeg_source("default"), FfmpegSource.default)
self.assertEqual(install.ffmpeg_source("8.0"), FfmpegSource.default)
self.assertEqual(install.ffmpeg_source("4.4"), FfmpegSource.default)
self.assertEqual(install.ffmpeg_source("7.0"), FfmpegSource.bundled)
self.assertEqual(
install.ffmpeg_source("/config/custom-ffmpeg"), FfmpegSource.custom
)
self.assertEqual(
install.ffmpeg_source("/config/a b; rm"), FfmpegSource.default
)
def test_custom_go2rtc_needs_an_executable_binary(self):
with tempfile.TemporaryDirectory() as config_dir:
binary = os.path.join(config_dir, "go2rtc")
with patch.object(install, "CONFIG_DIR", config_dir):
self.assertFalse(install.collect(make_context()).custom_go2rtc)
open(binary, "w").close()
self.assertFalse(install.collect(make_context()).custom_go2rtc)
os.chmod(binary, 0o755)
self.assertTrue(install.collect(make_context()).custom_go2rtc)
def test_image_variant_is_dev_when_unset_and_other_when_unknown(self):
self.assertEqual(install.image_variant(None), ImageVariant.dev)
+2
View File
@@ -25,6 +25,8 @@ INSTALL = InstallSection(
arch="x86_64",
kernel="6.8",
run_as_root=False,
custom_go2rtc=False,
ffmpeg="default",
)
+37
View File
@@ -1,5 +1,6 @@
"""Tests for migrating detectors and model into the models list."""
import errno
import logging
import os
import tempfile
@@ -240,6 +241,42 @@ class TestMigrateConfigFile(unittest.TestCase):
with open(self.config_file) as f:
return YAML().load(f)
def test_a_failed_write_leaves_the_original_config(self):
original = "mqtt:\n enabled: false\ncameras: {}\n"
with open(self.config_file, "w") as f:
f.write(original)
with (
patch.object(YAML, "dump", side_effect=RuntimeError),
self.assertRaises(RuntimeError),
):
migrate_frigate_config(self.config_file)
with open(self.config_file) as f:
self.assertEqual(f.read(), original)
def test_a_file_bind_mount_is_written_in_place(self):
with patch(
"frigate.util.config.os.replace",
side_effect=OSError(errno.EBUSY, "Device or resource busy"),
):
migrated = self._migrate("mqtt:\n enabled: false\ncameras: {}\n")
self.assertEqual(migrated["version"], CURRENT_CONFIG_VERSION)
self.assertFalse(os.path.exists(f"{self.config_file}.tmp"))
def test_a_symlinked_config_migrates_its_target(self):
target = os.path.join(self.temp_dir.name, "frigate.yml")
with open(target, "w") as f:
f.write("mqtt:\n enabled: false\ncameras: {}\n")
os.symlink(target, self.config_file)
migrate_frigate_config(self.config_file)
self.assertTrue(os.path.islink(self.config_file))
with open(target) as f:
self.assertEqual(YAML().load(f)["version"], CURRENT_CONFIG_VERSION)
def test_migrates_a_config_already_stamped_with_the_current_version(self):
# 0.19 is unreleased, so a dev config can be current and still use
# the pre-models keys
+30
View File
@@ -321,6 +321,36 @@ class TestLighterANE(unittest.TestCase):
ane.assert_not_called()
class TestTensorRTProvider(unittest.TestCase):
def _trt_options(self, env):
with (
patch.object(
model_util.ort,
"get_available_providers",
return_value=["TensorrtExecutionProvider", "CPUExecutionProvider"],
),
patch.object(model_util.os, "makedirs"),
patch.dict(os.environ, env, clear=False),
):
if "USE_FP16" not in env:
os.environ.pop("USE_FP16", None)
providers, options = model_util.get_ort_providers(device="Tensorrt")
return options[providers.index("TensorrtExecutionProvider")]
def test_fp16_is_disabled_by_default(self):
self.assertFalse(self._trt_options({})["trt_fp16_enable"])
def test_use_fp16_enables_fp16(self):
for value in ("true", "True", "TRUE"):
with self.subTest(value=value):
options = self._trt_options({"USE_FP16": value})
self.assertTrue(options["trt_fp16_enable"])
def test_use_fp16_false_keeps_fp16_disabled(self):
self.assertFalse(self._trt_options({"USE_FP16": "False"})["trt_fp16_enable"])
class TestMIGraphX(unittest.TestCase):
"""AMD's MIGraphX plugin provider, selected through its devices in the ROCm image."""
+33 -18
View File
@@ -1,6 +1,8 @@
"""configuration utils."""
import asyncio
import contextlib
import errno
import ipaddress
import logging
import os
@@ -212,6 +214,28 @@ def find_config_file() -> str:
return config_path
def _write_config(config_file: str, yaml: YAML, config: dict[str, Any]) -> None:
config_file = os.path.realpath(config_file)
st = os.stat(config_file)
tmp_file = f"{config_file}.tmp"
with open(tmp_file, "w") as f:
yaml.dump(config, f)
os.chmod(tmp_file, st.st_mode)
with contextlib.suppress(PermissionError):
os.chown(tmp_file, st.st_uid, st.st_gid)
try:
os.replace(tmp_file, config_file)
except OSError as e:
if e.errno != errno.EBUSY:
raise
# a file bind mount can't be renamed over, so write it in place
shutil.copyfile(tmp_file, config_file)
os.remove(tmp_file)
def migrate_frigate_config(config_file: str):
"""handle migrating the frigate config."""
logger.info("Checking if frigate config needs migration...")
@@ -259,8 +283,7 @@ def migrate_frigate_config(config_file: str):
if previous_version < "0.14":
logger.info(f"Migrating frigate config from {previous_version} to 0.14...")
new_config = migrate_014(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.14"
logger.info("Migrating export file names...")
@@ -277,56 +300,48 @@ def migrate_frigate_config(config_file: str):
if previous_version < "0.15-0":
logger.info(f"Migrating frigate config from {previous_version} to 0.15-0...")
new_config = migrate_015_0(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.15-0"
if previous_version < "0.15-1":
logger.info(f"Migrating frigate config from {previous_version} to 0.15-1...")
new_config = migrate_015_1(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.15-1"
if previous_version < "0.16-0":
logger.info(f"Migrating frigate config from {previous_version} to 0.16-0...")
new_config = migrate_016_0(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.16-0"
if previous_version < "0.17-0":
logger.info(f"Migrating frigate config from {previous_version} to 0.17-0...")
new_config = migrate_017_0(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.17-0"
if previous_version < "0.18-0":
logger.info(f"Migrating frigate config from {previous_version} to 0.18-0...")
new_config = migrate_018_0(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.18-0"
if previous_version < "0.19-0":
logger.info(f"Migrating frigate config from {previous_version} to 0.19-0...")
new_config = migrate_019_0(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
previous_version = "0.19-0"
if needs_models:
logger.info("Migrating frigate detectors and model to models...")
new_config = migrate_models(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
if needs_detector_rename:
logger.info("Migrating renamed frigate detectors...")
new_config = rename_hailo_detector(new_config)
with open(config_file, "w") as f:
yaml.dump(new_config, f)
_write_config(config_file, yaml, new_config)
logger.info("Finished frigate config migration...")
+2 -3
View File
@@ -318,7 +318,6 @@ def post_process_yolox(
def get_ort_providers(
force_cpu: bool = False,
device: str | None = "AUTO",
requires_fp16: bool = False,
) -> tuple[list[str], list[dict[str, Any]]]:
if force_cpu:
return (
@@ -357,8 +356,8 @@ def get_ort_providers(
options.append(
{
"device_id": device_id,
"trt_fp16_enable": requires_fp16
and os.environ.get("USE_FP16", "True") != "False",
"trt_fp16_enable": os.environ.get("USE_FP16", "False").lower()
== "true",
"trt_timing_cache_enable": True,
"trt_engine_cache_enable": True,
"trt_timing_cache_path": os.path.join(
+32 -32
View File
@@ -45,15 +45,15 @@
"copy-to-clipboard": "^4.0.2",
"date-fns": "^4.4.0",
"date-fns-tz": "^3.2.0",
"framer-motion": "^14.9.1",
"framer-motion": "^14.10.0",
"hls.js": "^1.7.4",
"i18next": "^26.7.1",
"i18next": "^26.7.2",
"i18next-http-backend": "^4.0.10",
"idb-keyval": "^6.3.0",
"js-yaml": "^5.5.0",
"konva": "^10.9.1",
"lodash": "^4.18.1",
"lucide-react": "^1.69.0",
"lucide-react": "^1.70.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.91.0",
"react-i18next": "^17.1.12",
"react-i18next": "^17.1.13",
"react-icons": "^5.7.0",
"react-konva": "^19.3.2",
"react-markdown": "^10.1.0",
@@ -87,7 +87,7 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.64.1",
"@playwright/test": "^1.65.0",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.27",
"@types/node": "^26.6.6",
@@ -1714,13 +1714,13 @@
}
},
"node_modules/@playwright/test": {
"version": "1.64.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.1.tgz",
"integrity": "sha512-IaYGml/nSOiZWROfPtuIL7neuu9qDOZ3TNvNljUIrhDMxiGTgPjzj/g9p9RxpS2tSepPDRY+UwAaEeiKtUvIAg==",
"version": "1.65.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.65.0.tgz",
"integrity": "sha512-iGURLGuKDLakSEl7Pgfv8h7f+XLT+V861Wfhz0zlEl5nyFuKUopdkFBPKqTllTUp06aOwPuH8iuUEb3yp3MpbQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.64.1"
"playwright": "1.65.0"
},
"bin": {
"playwright": "cli.js"
@@ -5596,12 +5596,12 @@
}
},
"node_modules/framer-motion": {
"version": "14.9.1",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-14.9.1.tgz",
"integrity": "sha512-WDWNT2ixHdmpvGg02BZWI/SWwRYzPiMUf4aIkTBgrxxD8RYFdZO3fCM4pnLMo6j8mUpj0+BuJRHQBChI4v3Anw==",
"version": "14.10.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-14.10.0.tgz",
"integrity": "sha512-e8MjIet+IJKohYxBj8TAk9Mg5cD0HiOX87qde1YTPL67gI2ao074O6yBtQnIcWCk+bTX7XX4litepufLiYPrLg==",
"license": "MIT",
"dependencies": {
"motion-dom": "14.9.1",
"motion-dom": "14.10.0",
"motion-utils": "14.7.0",
"tslib": "^2.4.0"
},
@@ -6009,9 +6009,9 @@
}
},
"node_modules/i18next": {
"version": "26.7.1",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.7.1.tgz",
"integrity": "sha512-cX+3RRVczel/V2kCMTACckSGSpqgtWYEA6beXNYVms7dOQiHojdPYHD26lT4IKimNeoGWrLvtPgjftbRvmZJVw==",
"version": "26.7.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.7.2.tgz",
"integrity": "sha512-RsOY3BeaCDdkk52NeJSFAXELQ2rQXBO/tOub6L8ue2ICPfR/FRDWDOfEDg4xMPd1SqO5goVYQ6i72qWEUB/PPw==",
"funding": [
{
"type": "individual",
@@ -6996,9 +6996,9 @@
}
},
"node_modules/lucide-react": {
"version": "1.69.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.69.0.tgz",
"integrity": "sha512-UTFECm4yEgkgMN0kfLuxWcmlk+4u02Jrqehgk3ZXRx/Ud68OpP7hjkp67bvkBHmIpMaZCIveF1QDYeupO7XmYQ==",
"version": "1.70.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.70.0.tgz",
"integrity": "sha512-gCTPPN1MlQUBtUgdsUv+0CAUj+X8hifRUiRBw4E5v7lvDIOIpx0EZezdGQMSimS8pKA6esvullJub4GYr0mCHA==",
"license": "ISC",
"peerDependencies": {
"@types/react": "*",
@@ -8073,9 +8073,9 @@
}
},
"node_modules/motion-dom": {
"version": "14.9.1",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-14.9.1.tgz",
"integrity": "sha512-2eCCGXH2Yv09lM8GHK3TdfChrcvHxzVY19LD9VraoHEaQl5+PuGnTNnmJaBAR+5MdxUVdsLFXygFJjR9RwRSxw==",
"version": "14.10.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-14.10.0.tgz",
"integrity": "sha512-k0LwJZ1R5xCvqrScszO4ywuZP52lRcT3QO0IUovgczom9ZHb0BaRLOX6M2O40q7TrSLvzX/fIHHmDm8TUMt3fg==",
"license": "MIT",
"dependencies": {
"motion-utils": "14.7.0"
@@ -8537,13 +8537,13 @@
}
},
"node_modules/playwright": {
"version": "1.64.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz",
"integrity": "sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==",
"version": "1.65.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.65.0.tgz",
"integrity": "sha512-F3AMWcR44qMBt4kq+6Kb6mX7bjGXshktKFOPULd7reED6ZJWevjbNRqysP7q+AATE9kdPEZBibex1BYsvpVoeA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.64.1"
"playwright-core": "1.65.0"
},
"bin": {
"playwright": "cli.js"
@@ -8553,9 +8553,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.64.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz",
"integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==",
"version": "1.65.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.65.0.tgz",
"integrity": "sha512-vNSKgH6YqtN7cdT/L334zo0a+YwkrpicyrHJlWWPIm/Q+Nn2SWInil01oT0mbu96U4GgoRtCYQD9CzJQgju+lA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -9077,9 +9077,9 @@
}
},
"node_modules/react-i18next": {
"version": "17.1.12",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.1.12.tgz",
"integrity": "sha512-Gf8riCKF/EmqQ8I1g0N5pJOLvJCkAXGAEkzOuRNHc/sBGL3dfE3WZ7+sDLrUo/kw/xdug3g48jo7M+s/SKf0HQ==",
"version": "17.1.13",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.1.13.tgz",
"integrity": "sha512-ZxhOSlyKSKPtbUNPLwYMmE3w3bhoc0jaZJZ6bc7wGOT6cLbrbs//6m01HxCLtFdSjHvFpwFwoPhxxzIlHSs9cw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.7",
+5 -5
View File
@@ -57,15 +57,15 @@
"copy-to-clipboard": "^4.0.2",
"date-fns": "^4.4.0",
"date-fns-tz": "^3.2.0",
"framer-motion": "^14.9.1",
"framer-motion": "^14.10.0",
"hls.js": "^1.7.4",
"i18next": "^26.7.1",
"i18next": "^26.7.2",
"i18next-http-backend": "^4.0.10",
"idb-keyval": "^6.3.0",
"js-yaml": "^5.5.0",
"konva": "^10.9.1",
"lodash": "^4.18.1",
"lucide-react": "^1.69.0",
"lucide-react": "^1.70.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.91.0",
"react-i18next": "^17.1.12",
"react-i18next": "^17.1.13",
"react-icons": "^5.7.0",
"react-konva": "^19.3.2",
"react-markdown": "^10.1.0",
@@ -99,7 +99,7 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.64.1",
"@playwright/test": "^1.65.0",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.17.27",
"@types/node": "^26.6.6",