diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 01b91624c..a24a94dcf 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,7 +67,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Install python
uses: actions/setup-python@v6
with:
@@ -81,7 +81,7 @@ jobs:
- pre-commit
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up Python
id: setup-python
uses: actions/setup-python@v6
@@ -131,7 +131,7 @@ jobs:
fail-fast: false
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Start containers
run: |
docker compose --file ${{ github.workspace }}/docker/compose/docker-compose.ci-test.yml pull --quiet
@@ -202,7 +202,7 @@ jobs:
needs:
- pre-commit
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
@@ -235,7 +235,7 @@ jobs:
shard-index: [1, 2, 3, 4]
shard-count: [4]
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
@@ -284,7 +284,7 @@ jobs:
shard-index: [1, 2]
shard-count: [2]
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
@@ -327,7 +327,7 @@ jobs:
- tests-frontend
- tests-frontend-e2e
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
@@ -424,7 +424,7 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
# If https://github.com/docker/buildx/issues/1044 is resolved,
# the append input with a native arm64 arch could be used to
# significantly speed up building
@@ -503,7 +503,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up Python
id: setup-python
uses: actions/setup-python@v6
@@ -649,7 +649,7 @@ jobs:
if: needs.publish-release.outputs.prerelease == 'false'
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
ref: main
- name: Set up Python
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 77913ba81..941d83648 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -34,7 +34,7 @@ jobs:
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml
index b4b4cd2ac..29fb4c181 100644
--- a/.github/workflows/crowdin.yml
+++ b/.github/workflows/crowdin.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
token: ${{ secrets.PNGX_BOT_PAT }}
- name: crowdin action
diff --git a/.github/workflows/translate-strings.yml b/.github/workflows/translate-strings.yml
index a3326cbcf..bd9eafae5 100644
--- a/.github/workflows/translate-strings.yml
+++ b/.github/workflows/translate-strings.yml
@@ -11,7 +11,7 @@ jobs:
contents: write
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
with:
token: ${{ secrets.PNGX_BOT_PAT }}
ref: ${{ github.head_ref }}
diff --git a/src-ui/messages.xlf b/src-ui/messages.xlf
index 48c54782d..c48eba6e9 100644
--- a/src-ui/messages.xlf
+++ b/src-ui/messages.xlf
@@ -5,14 +5,14 @@
Close
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/alert/alert.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/alert/alert.ts
50
Slide of
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/carousel/carousel.ts
131,135
Currently selected slide number read by screen reader
@@ -20,212 +20,212 @@
Previous
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/carousel/carousel.ts
157,159
Next
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/carousel/carousel.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/carousel/carousel.ts
198
Previous month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/datepicker/datepicker-navigation.ts
83,85
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/datepicker/datepicker-navigation.ts
112
Next month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/datepicker/datepicker-navigation.ts
112
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/datepicker/datepicker-navigation.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/datepicker/datepicker-navigation.ts
112
HH
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Close
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Select month
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
MM
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Select year
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Increment hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Decrement hours
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Increment minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Decrement minutes
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
SS
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Increment seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
Decrement seconds
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/ngb-config.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/ngb-config.ts
13
@@ -233,7 +233,7 @@
- node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.14_@angular+core@20.3.12_@angula_f6978d5a33be250eb7b5e8e65faf7a7d/node_modules/src/progressbar/progressbar.ts
+ node_modules/.pnpm/@ng-bootstrap+ng-bootstrap@19.0.1_@angular+common@20.3.15_@angular+core@20.3.15_@angula_40533c760dbaadbd90323f0d78d15fb8/node_modules/src/progressbar/progressbar.ts
41,42
diff --git a/src-ui/package.json b/src-ui/package.json
index f3d04a628..c0ff9dea6 100644
--- a/src-ui/package.json
+++ b/src-ui/package.json
@@ -12,14 +12,14 @@
"private": true,
"dependencies": {
"@angular/cdk": "^20.2.13",
- "@angular/common": "~20.3.14",
- "@angular/compiler": "~20.3.12",
- "@angular/core": "~20.3.12",
- "@angular/forms": "~20.3.12",
- "@angular/localize": "~20.3.12",
- "@angular/platform-browser": "~20.3.12",
- "@angular/platform-browser-dynamic": "~20.3.12",
- "@angular/router": "~20.3.12",
+ "@angular/common": "~20.3.15",
+ "@angular/compiler": "~20.3.15",
+ "@angular/core": "~20.3.15",
+ "@angular/forms": "~20.3.15",
+ "@angular/localize": "~20.3.15",
+ "@angular/platform-browser": "~20.3.15",
+ "@angular/platform-browser-dynamic": "~20.3.15",
+ "@angular/router": "~20.3.15",
"@ng-bootstrap/ng-bootstrap": "^19.0.1",
"@ng-select/ng-select": "^20.7.0",
"@ngneat/dirty-check-forms": "^3.0.3",
@@ -42,16 +42,16 @@
"devDependencies": {
"@angular-builders/custom-webpack": "^20.0.0",
"@angular-builders/jest": "^20.0.0",
- "@angular-devkit/core": "^20.3.10",
- "@angular-devkit/schematics": "^20.3.10",
+ "@angular-devkit/core": "^20.3.13",
+ "@angular-devkit/schematics": "^20.3.13",
"@angular-eslint/builder": "20.6.0",
"@angular-eslint/eslint-plugin": "20.6.0",
"@angular-eslint/eslint-plugin-template": "20.6.0",
"@angular-eslint/schematics": "20.6.0",
"@angular-eslint/template-parser": "20.6.0",
- "@angular/build": "^20.3.10",
- "@angular/cli": "~20.3.10",
- "@angular/compiler-cli": "~20.3.12",
+ "@angular/build": "^20.3.13",
+ "@angular/cli": "~20.3.13",
+ "@angular/compiler-cli": "~20.3.15",
"@codecov/webpack-plugin": "^1.9.1",
"@playwright/test": "^1.57.0",
"@types/jest": "^30.0.0",
diff --git a/src-ui/pnpm-lock.yaml b/src-ui/pnpm-lock.yaml
index e86f48c8d..a57b78864 100644
--- a/src-ui/pnpm-lock.yaml
+++ b/src-ui/pnpm-lock.yaml
@@ -10,40 +10,40 @@ importers:
dependencies:
'@angular/cdk':
specifier: ^20.2.13
- version: 20.2.13(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ version: 20.2.13(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
'@angular/common':
- specifier: ~20.3.14
- version: 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
'@angular/compiler':
- specifier: ~20.3.12
- version: 20.3.12
+ specifier: ~20.3.15
+ version: 20.3.15
'@angular/core':
- specifier: ~20.3.12
- version: 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
'@angular/forms':
- specifier: ~20.3.12
- version: 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@angular/localize':
- specifier: ~20.3.12
- version: 20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)
'@angular/platform-browser':
- specifier: ~20.3.12
- version: 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
'@angular/platform-browser-dynamic':
- specifier: ~20.3.12
- version: 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))
'@angular/router':
- specifier: ~20.3.12
- version: 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@ng-bootstrap/ng-bootstrap':
specifier: ^19.0.1
- version: 19.0.1(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@popperjs/core@2.11.8)(rxjs@7.8.2)
+ version: 19.0.1(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@popperjs/core@2.11.8)(rxjs@7.8.2)
'@ng-select/ng-select':
specifier: ^20.7.0
- version: 20.7.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))
+ version: 20.7.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))
'@ngneat/dirty-check-forms':
specifier: ^3.0.3
- version: 3.0.3(8ff1ffec9c0eb3e42a8b58cc79f67aaa)
+ version: 3.0.3(218c118fbd72b8c5b4f5fd1fa1211ac5)
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
@@ -61,19 +61,19 @@ importers:
version: 10.4.0
ngx-bootstrap-icons:
specifier: ^1.9.3
- version: 1.9.3(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ version: 1.9.3(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
ngx-color:
specifier: ^10.1.0
- version: 10.1.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ version: 10.1.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
ngx-cookie-service:
specifier: ^20.1.1
- version: 20.1.1(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ version: 20.1.1(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
ngx-device-detector:
specifier: ^10.1.0
- version: 10.1.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ version: 10.1.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
ngx-ui-tour-ng-bootstrap:
specifier: ^17.0.1
- version: 17.0.1(1990d937b48b356c3a7b81a3382c7bae)
+ version: 17.0.1(43e0b240967005bbda3e3b71e72070f1)
rxjs:
specifier: ^7.8.2
version: 7.8.2
@@ -92,16 +92,16 @@ importers:
devDependencies:
'@angular-builders/custom-webpack':
specifier: ^20.0.0
- version: 20.0.0(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
+ version: 20.0.0(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
'@angular-builders/jest':
specifier: ^20.0.0
- version: 20.0.0(2a2dc918d42153e5c2c5a3eb18182c36)
+ version: 20.0.0(6f21bd249f8e5dee2ad8e6487b28db46)
'@angular-devkit/core':
- specifier: ^20.3.10
- version: 20.3.10(chokidar@4.0.3)
+ specifier: ^20.3.13
+ version: 20.3.13(chokidar@4.0.3)
'@angular-devkit/schematics':
- specifier: ^20.3.10
- version: 20.3.10(chokidar@4.0.3)
+ specifier: ^20.3.13
+ version: 20.3.13(chokidar@4.0.3)
'@angular-eslint/builder':
specifier: 20.6.0
version: 20.6.0(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
@@ -118,14 +118,14 @@ importers:
specifier: 20.6.0
version: 20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular/build':
- specifier: ^20.3.10
- version: 20.3.10(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
+ specifier: ^20.3.13
+ version: 20.3.13(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
'@angular/cli':
- specifier: ~20.3.10
- version: 20.3.10(@types/node@24.10.1)(chokidar@4.0.3)
+ specifier: ~20.3.13
+ version: 20.3.13(@types/node@24.10.1)(chokidar@4.0.3)
'@angular/compiler-cli':
- specifier: ~20.3.12
- version: 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ specifier: ~20.3.15
+ version: 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
'@codecov/webpack-plugin':
specifier: ^1.9.1
version: 1.9.1(webpack@5.103.0)
@@ -161,7 +161,7 @@ importers:
version: 16.0.0
jest-preset-angular:
specifier: ^15.0.3
- version: 15.0.3(138e950b6256ba9944139a8c5aad3bdf)
+ version: 15.0.3(e164a15bea80c603eb581d5724a352ec)
jest-websocket-mock:
specifier: ^2.5.0
version: 2.5.0
@@ -283,6 +283,10 @@ packages:
resolution: {integrity: sha512-2SWetxJzS8gRX6OKQstkWx37VRvZVgcEBDLsDSaeTjpnwh81A+niZQjAVRdwL0NEt1Wixk/RxfeUuCmdyyHvhQ==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
+ '@angular-devkit/architect@0.2003.13':
+ resolution: {integrity: sha512-JyH6Af6PNC1IHJToColFk1RaXDU87mpPjz7M5sWDfn8bC+KBipw6dSdRkCEuw0D9HY1lZkC9EBV9k9GhpvHjCQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
+
'@angular-devkit/build-angular@20.0.4':
resolution: {integrity: sha512-YUf9hRAd//yu44vGMnET1ajmUMXwSz0t4rOajDj5yb57sYS9eYu912K2pWfDNDNJncOshtpklvBqUDngDNcPDw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
@@ -358,8 +362,17 @@ packages:
chokidar:
optional: true
- '@angular-devkit/schematics@20.3.10':
- resolution: {integrity: sha512-2N2WF9lj+kr3uCG4+vFadYCL5hAT4dxMgzwScSdOqSd0O+GZD0CzKbDzlfvWIWC/ZealC5Sh4dFEQaRfmy72xA==}
+ '@angular-devkit/core@20.3.13':
+ resolution: {integrity: sha512-/D84T1Caxll3I2sRihPDR9UaWBhF50M+tAX15PdP6uSh/TxwAlLl9p7Rm1bD0mPjPercqaEKA+h9a9qLP16hug==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
+ peerDependencies:
+ chokidar: ^4.0.0
+ peerDependenciesMeta:
+ chokidar:
+ optional: true
+
+ '@angular-devkit/schematics@20.3.13':
+ resolution: {integrity: sha512-hdMKY4rUTko8xqeWYGnwwDYDomkeOoLsYsP6SdaHWK7hpGvzWsT6Q/aIv8J8NrCYkLu+M+5nLiKOooweUZu3GQ==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
'@angular-eslint/builder@20.6.0':
@@ -449,8 +462,8 @@ packages:
vitest:
optional: true
- '@angular/build@20.3.10':
- resolution: {integrity: sha512-nQrj1nMNZygYDilThc7hPrD6/NIWF/BOSgMfE4VkXQp8d0QronP3HFJ/h77MeoughMRFRhix0pqQSlXJQ2SGTQ==}
+ '@angular/build@20.3.13':
+ resolution: {integrity: sha512-/5pM3ZS+lLkZgA+n6TMmNV8I6t9Ow1C6Vkj6bXqWeOgFDH5LwnIEZFAKzEDBkCGos0m2gPKPcREcDD5tfp9h4g==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
'@angular/compiler': ^20.0.0
@@ -460,7 +473,7 @@ packages:
'@angular/platform-browser': ^20.0.0
'@angular/platform-server': ^20.0.0
'@angular/service-worker': ^20.0.0
- '@angular/ssr': ^20.3.10
+ '@angular/ssr': ^20.3.13
karma: ^6.4.0
less: ^4.2.0
ng-packagr: ^20.0.0
@@ -502,38 +515,38 @@ packages:
'@angular/core': ^20.0.0 || ^21.0.0
rxjs: ^6.5.3 || ^7.4.0
- '@angular/cli@20.3.10':
- resolution: {integrity: sha512-CQzXScurBXSuMMn0jf6UYDItdggaM3bHYERKL4cUG1z5JqSozVFin1+TB1EjWYkddwdgC10R5xQurdMb+ahRNw==}
+ '@angular/cli@20.3.13':
+ resolution: {integrity: sha512-G78I/HDJULloS2LSqfUfbmBlhDCbcWujIRWfuMnGsRf82TyGA2OEPe3IA/F8MrJfeOzPQim2fMyn24MqHL40Vg==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
hasBin: true
- '@angular/common@20.3.14':
- resolution: {integrity: sha512-OOUvjTtnpktJLsNupA+GFT2q5zNocPdpOENA8aSrXvAheNybLjgi+otO3U3sQsvB1VwaoEZ9GT5O3lZlstnA/A==}
+ '@angular/common@20.3.15':
+ resolution: {integrity: sha512-k4mCXWRFiOHK3bUKfWkRQQ8KBPxW8TAJuKLYCsSHPCpMz6u0eA1F0VlrnOkZVKWPI792fOaEAWH2Y4PTaXlUHw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/core': 20.3.14
+ '@angular/core': 20.3.15
rxjs: ^6.5.3 || ^7.4.0
- '@angular/compiler-cli@20.3.12':
- resolution: {integrity: sha512-3SJkexqsydYjIs0iLiJr5AdwkvumpzvjJM6s76iaxXHkRll5k/vM0wqkXLlSIwieBrecO9D4J73lDLWDevXl5A==}
+ '@angular/compiler-cli@20.3.15':
+ resolution: {integrity: sha512-8sJoxodxsfyZ8eJ5r6Bx7BCbazXYgsZ1+dE8t5u5rTQ6jNggwNtYEzkyReoD5xvP+MMtRkos3xpwq4rtFnpI6A==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
hasBin: true
peerDependencies:
- '@angular/compiler': 20.3.12
+ '@angular/compiler': 20.3.15
typescript: '>=5.8 <6.0'
peerDependenciesMeta:
typescript:
optional: true
- '@angular/compiler@20.3.12':
- resolution: {integrity: sha512-bGESKz97nWiEQ/sydTq/Lzv3zlLvDb8t0msLG5Xti7Ch1EdLddXS8d2D/zFsjiGbAUKVsT6RgPCLHYoi4ocbhA==}
+ '@angular/compiler@20.3.15':
+ resolution: {integrity: sha512-lMicIAFAKZXa+BCZWs3soTjNQPZZXrF/WMVDinm8dQcggNarnDj4UmXgKSyXkkyqK5SLfnLsXVzrX6ndVT6z7A==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
- '@angular/core@20.3.12':
- resolution: {integrity: sha512-K7vibMr55a7+EsuDhkg4Pk+ELuMm12olllwqL/CiQUcHXZ9Zgc4KYGTUuxWB69qJCG90gdSZS7tm5Dx0wDcyjg==}
+ '@angular/core@20.3.15':
+ resolution: {integrity: sha512-NMbX71SlTZIY9+rh/SPhRYFJU0pMJYW7z/TBD4lqiO+b0DTOIg1k7Pg9ydJGqSjFO1Z4dQaA6TteNuF99TJCNw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/compiler': 20.3.12
+ '@angular/compiler': 20.3.15
rxjs: ^6.5.3 || ^7.4.0
zone.js: ~0.15.0
peerDependenciesMeta:
@@ -542,50 +555,50 @@ packages:
zone.js:
optional: true
- '@angular/forms@20.3.12':
- resolution: {integrity: sha512-O0Jy8ScaN3qVipDfR4s0SIxGrz/+MbCdmR05ZYVWf1W5P3dvETKt9WNjX9fYYV47GdgSveyFjuCR2NvWlv94zA==}
+ '@angular/forms@20.3.15':
+ resolution: {integrity: sha512-gS5hQkinq52pm/7mxz4yHPCzEcmRWjtUkOVddPH0V1BW/HMni/p4Y6k2KqKBeGb9p8S5EAp6PDxDVLOPukp3mg==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/common': 20.3.12
- '@angular/core': 20.3.12
- '@angular/platform-browser': 20.3.12
+ '@angular/common': 20.3.15
+ '@angular/core': 20.3.15
+ '@angular/platform-browser': 20.3.15
rxjs: ^6.5.3 || ^7.4.0
- '@angular/localize@20.3.12':
- resolution: {integrity: sha512-wolRAeaWCh6kLNZitrlnQYm9nPaGQ2OwO04I10p1dEY2gC/nCMdJvh3umaOHTD2lN64ebZUxS5gJS8+PPTOcmg==}
+ '@angular/localize@20.3.15':
+ resolution: {integrity: sha512-vJDLXzQgLE+zpzwT2n85yWmWHuk9BsnPByOHyF63K178GFs0TG49UqZOFKohGbq5Vlo1GI9NIvXkcegkoMJCMQ==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
hasBin: true
peerDependencies:
- '@angular/compiler': 20.3.12
- '@angular/compiler-cli': 20.3.12
+ '@angular/compiler': 20.3.15
+ '@angular/compiler-cli': 20.3.15
- '@angular/platform-browser-dynamic@20.3.12':
- resolution: {integrity: sha512-VviTUCpcbwErQjWd+EZklQf1Fw1FtXui6ey4rEb9g9mCEJ/o08LkM7mWV5IoE6QNCfbgkfgNjEJSJvWe409Mow==}
+ '@angular/platform-browser-dynamic@20.3.15':
+ resolution: {integrity: sha512-RizuRdBt0d6ongQ2y8cr8YsXFyjF8f91vFfpSNw+cFj+oiEmRC1txcWUlH5bPLD9qSDied8qazUi0Tb8VPQDGw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/common': 20.3.12
- '@angular/compiler': 20.3.12
- '@angular/core': 20.3.12
- '@angular/platform-browser': 20.3.12
+ '@angular/common': 20.3.15
+ '@angular/compiler': 20.3.15
+ '@angular/core': 20.3.15
+ '@angular/platform-browser': 20.3.15
- '@angular/platform-browser@20.3.12':
- resolution: {integrity: sha512-14KQsXZyaQhbRwFz1W58CtbXQc9L+mfuHBgwQjQo99422Yk0ye5WVMb6DHH7dH671qFVqL0XL7zdOPBebaAnJQ==}
+ '@angular/platform-browser@20.3.15':
+ resolution: {integrity: sha512-TxRM/wTW/oGXv/3/Iohn58yWoiYXOaeEnxSasiGNS1qhbkcKtR70xzxW6NjChBUYAixz2ERkLURkpx3pI8Q6Dw==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/animations': 20.3.12
- '@angular/common': 20.3.12
- '@angular/core': 20.3.12
+ '@angular/animations': 20.3.15
+ '@angular/common': 20.3.15
+ '@angular/core': 20.3.15
peerDependenciesMeta:
'@angular/animations':
optional: true
- '@angular/router@20.3.12':
- resolution: {integrity: sha512-hUipb9JI/Euy3bdlhzkcWlw3cTyssPTVTDwSvyGxWO4i+UKATQYmxh8EDOrDYzFp6Aexiy0Hff/H8umdsn6ZdA==}
+ '@angular/router@20.3.15':
+ resolution: {integrity: sha512-6+qgk8swGSoAu7ISSY//GatAyCP36hEvvUgvjbZgkXLLH9yUQxdo77ij05aJ5s0OyB25q/JkqS8VTY0z1yE9NQ==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
- '@angular/common': 20.3.12
- '@angular/core': 20.3.12
- '@angular/platform-browser': 20.3.12
+ '@angular/common': 20.3.15
+ '@angular/core': 20.3.15
+ '@angular/platform-browser': 20.3.15
rxjs: ^6.5.3 || ^7.4.0
'@asamuzakjp/css-color@3.2.0':
@@ -2200,9 +2213,15 @@ packages:
cpu: [x64]
os: [win32]
- '@modelcontextprotocol/sdk@1.17.3':
- resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==}
+ '@modelcontextprotocol/sdk@1.24.0':
+ resolution: {integrity: sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==}
engines: {node: '>=18'}
+ peerDependencies:
+ '@cfworker/json-schema': ^4.1.1
+ zod: ^3.25 || ^4.0
+ peerDependenciesMeta:
+ '@cfworker/json-schema':
+ optional: true
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
@@ -2783,8 +2802,8 @@ packages:
cpu: [x64]
os: [win32]
- '@schematics/angular@20.3.10':
- resolution: {integrity: sha512-F9ntS2CElpoWlENf4b03nwdTcN9Ri0Nb4SAE/pfRw3In09h2UHxYyf1ex9jqQt70xltDg4wvyuc3mMs+JlSx9A==}
+ '@schematics/angular@20.3.13':
+ resolution: {integrity: sha512-ETJ1budKmrkdxojo5QP6TPr6zQZYGxtWWf8NrX1cBIS851zPCmFkKyhSFLZsoksariYF/LP8ljvm8tlcIzt/XA==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
'@sigstore/bundle@3.1.0':
@@ -3404,10 +3423,6 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
- baseline-browser-mapping@2.8.29:
- resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==}
- hasBin: true
-
baseline-browser-mapping@2.9.4:
resolution: {integrity: sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA==}
hasBin: true
@@ -3465,11 +3480,6 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.28.0:
- resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -3520,9 +3530,6 @@ packages:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
- caniuse-lite@1.0.30001755:
- resolution: {integrity: sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==}
-
caniuse-lite@1.0.30001759:
resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==}
@@ -3905,9 +3912,6 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- electron-to-chromium@1.5.255:
- resolution: {integrity: sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ==}
-
electron-to-chromium@1.5.266:
resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==}
@@ -4899,6 +4903,9 @@ packages:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -6556,12 +6563,6 @@ packages:
unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
- update-browserslist-db@1.1.4:
- resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
update-browserslist-db@1.2.2:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==}
hasBin: true
@@ -6930,14 +6931,17 @@ packages:
resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
engines: {node: '>=18'}
- zod-to-json-schema@3.24.6:
- resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
+ zod-to-json-schema@3.25.0:
+ resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==}
peerDependencies:
- zod: ^3.24.1
+ zod: ^3.25 || ^4
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+ zod@4.1.13:
+ resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==}
+
zone.js@0.15.1:
resolution: {integrity: sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==}
@@ -7060,7 +7064,7 @@ snapshots:
'@angular-builders/common@4.0.0(@types/node@24.10.1)(chokidar@4.0.3)(typescript@5.8.3)':
dependencies:
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.8.3)
tsconfig-paths: 4.2.0
transitivePeerDependencies:
@@ -7070,14 +7074,14 @@ snapshots:
- chokidar
- typescript
- '@angular-builders/custom-webpack@20.0.0(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)':
+ '@angular-builders/custom-webpack@20.0.0(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)':
dependencies:
'@angular-builders/common': 4.0.0(@types/node@24.10.1)(chokidar@4.0.3)(typescript@5.8.3)
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
- '@angular-devkit/build-angular': 20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
- '@angular/build': 20.3.10(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular-devkit/build-angular': 20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ '@angular/build': 20.3.13(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
lodash: 4.17.21
webpack-merge: 6.0.1
transitivePeerDependencies:
@@ -7124,17 +7128,17 @@ snapshots:
- webpack-cli
- yaml
- '@angular-builders/jest@20.0.0(2a2dc918d42153e5c2c5a3eb18182c36)':
+ '@angular-builders/jest@20.0.0(6f21bd249f8e5dee2ad8e6487b28db46)':
dependencies:
'@angular-builders/common': 4.0.0(@types/node@24.10.1)(chokidar@4.0.3)(typescript@5.8.3)
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
- '@angular-devkit/build-angular': 20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser-dynamic': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))
+ '@angular-devkit/build-angular': 20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser-dynamic': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))
jest: 30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3))
- jest-preset-angular: 14.6.0(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(canvas@3.0.0)(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jsdom@26.1.0(canvas@3.0.0))(typescript@5.8.3)
+ jest-preset-angular: 14.6.0(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(canvas@3.0.0)(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jsdom@26.1.0(canvas@3.0.0))(typescript@5.8.3)
lodash: 4.17.21
transitivePeerDependencies:
- '@babel/core'
@@ -7166,14 +7170,21 @@ snapshots:
transitivePeerDependencies:
- chokidar
- '@angular-devkit/build-angular@20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)':
+ '@angular-devkit/architect@0.2003.13(chokidar@4.0.3)':
+ dependencies:
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ rxjs: 7.8.2
+ transitivePeerDependencies:
+ - chokidar
+
+ '@angular-devkit/build-angular@20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jest-environment-jsdom@30.2.0(canvas@3.0.0))(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))(yaml@2.7.0)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
'@angular-devkit/build-webpack': 0.2000.4(chokidar@4.0.3)(webpack-dev-server@5.2.1(webpack@5.103.0))(webpack@5.99.8(esbuild@0.25.5))
'@angular-devkit/core': 20.0.4(chokidar@4.0.3)
- '@angular/build': 20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular/build': 20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
'@babel/core': 7.27.1
'@babel/generator': 7.27.1
'@babel/helper-annotate-as-pure': 7.27.1
@@ -7184,7 +7195,7 @@ snapshots:
'@babel/preset-env': 7.27.2(@babel/core@7.27.1)
'@babel/runtime': 7.27.1
'@discoveryjs/json-ext': 0.6.3
- '@ngtools/webpack': 20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.99.8(esbuild@0.25.5))
+ '@ngtools/webpack': 20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.99.8(esbuild@0.25.5))
'@vitejs/plugin-basic-ssl': 2.0.0(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))
ansi-colors: 4.1.3
autoprefixer: 10.4.21(postcss@8.5.3)
@@ -7226,9 +7237,9 @@ snapshots:
webpack-merge: 6.0.1
webpack-subresource-integrity: 5.1.0(webpack@5.99.8(esbuild@0.25.5))
optionalDependencies:
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/localize': 20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/localize': 20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
esbuild: 0.25.5
jest: 30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3))
jest-environment-jsdom: 30.2.0(canvas@3.0.0)
@@ -7287,9 +7298,20 @@ snapshots:
optionalDependencies:
chokidar: 4.0.3
- '@angular-devkit/schematics@20.3.10(chokidar@4.0.3)':
+ '@angular-devkit/core@20.3.13(chokidar@4.0.3)':
dependencies:
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
+ jsonc-parser: 3.3.1
+ picomatch: 4.0.3
+ rxjs: 7.8.2
+ source-map: 0.7.6
+ optionalDependencies:
+ chokidar: 4.0.3
+
+ '@angular-devkit/schematics@20.3.13(chokidar@4.0.3)':
+ dependencies:
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
jsonc-parser: 3.3.1
magic-string: 0.30.17
ora: 8.2.0
@@ -7300,7 +7322,7 @@ snapshots:
'@angular-eslint/builder@20.6.0(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
'@angular-devkit/architect': 0.2003.10(chokidar@4.0.3)
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
transitivePeerDependencies:
@@ -7331,8 +7353,8 @@ snapshots:
'@angular-eslint/schematics@20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)':
dependencies:
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
- '@angular-devkit/schematics': 20.3.10(chokidar@4.0.3)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ '@angular-devkit/schematics': 20.3.13(chokidar@4.0.3)
'@angular-eslint/eslint-plugin': 20.6.0(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
'@angular-eslint/eslint-plugin-template': 20.6.0(@angular-eslint/template-parser@20.6.0(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.48.1)(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.8.3)
ignore: 7.0.5
@@ -7360,12 +7382,12 @@ snapshots:
eslint: 9.39.1(jiti@1.21.7)
typescript: 5.8.3
- '@angular/build@20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)':
+ '@angular/build@20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.2000.4(chokidar@4.0.3)
- '@angular/compiler': 20.3.12
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular/compiler': 20.3.15
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
'@babel/core': 7.27.1
'@babel/helper-annotate-as-pure': 7.27.1
'@babel/helper-split-export-declaration': 7.24.7
@@ -7393,9 +7415,9 @@ snapshots:
vite: 6.3.5(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(yaml@2.7.0)
watchpack: 2.4.2
optionalDependencies:
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/localize': 20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/localize': 20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
less: 4.3.0
lmdb: 3.3.0
postcss: 8.5.3
@@ -7412,19 +7434,19 @@ snapshots:
- tsx
- yaml
- '@angular/build@20.3.10(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)':
+ '@angular/build@20.3.13(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.10.1)(chokidar@4.0.3)(jiti@1.21.7)(less@4.3.0)(postcss@8.5.3)(terser@5.39.1)(tslib@2.8.1)(typescript@5.8.3)(yaml@2.7.0)':
dependencies:
'@ampproject/remapping': 2.3.0
- '@angular-devkit/architect': 0.2003.10(chokidar@4.0.3)
- '@angular/compiler': 20.3.12
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular-devkit/architect': 0.2003.13(chokidar@4.0.3)
+ '@angular/compiler': 20.3.15
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
'@babel/core': 7.28.3
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-split-export-declaration': 7.24.7
'@inquirer/confirm': 5.1.14(@types/node@24.10.1)
'@vitejs/plugin-basic-ssl': 2.1.0(vite@7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0))
beasties: 0.3.5
- browserslist: 4.28.0
+ browserslist: 4.28.1
esbuild: 0.25.9
https-proxy-agent: 7.0.6
istanbul-lib-instrument: 6.0.3
@@ -7445,9 +7467,9 @@ snapshots:
vite: 7.1.11(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.90.0)(terser@5.39.1)(yaml@2.7.0)
watchpack: 2.4.4
optionalDependencies:
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/localize': 20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/localize': 20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
less: 4.3.0
lmdb: 3.4.2
postcss: 8.5.3
@@ -7464,23 +7486,23 @@ snapshots:
- tsx
- yaml
- '@angular/cdk@20.2.13(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)':
+ '@angular/cdk@20.2.13(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
parse5: 8.0.0
rxjs: 7.8.2
tslib: 2.8.1
- '@angular/cli@20.3.10(@types/node@24.10.1)(chokidar@4.0.3)':
+ '@angular/cli@20.3.13(@types/node@24.10.1)(chokidar@4.0.3)':
dependencies:
- '@angular-devkit/architect': 0.2003.10(chokidar@4.0.3)
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
- '@angular-devkit/schematics': 20.3.10(chokidar@4.0.3)
+ '@angular-devkit/architect': 0.2003.13(chokidar@4.0.3)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ '@angular-devkit/schematics': 20.3.13(chokidar@4.0.3)
'@inquirer/prompts': 7.8.2(@types/node@24.10.1)
'@listr2/prompt-adapter-inquirer': 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.10.1))(@types/node@24.10.1)(listr2@9.0.1)
- '@modelcontextprotocol/sdk': 1.17.3
- '@schematics/angular': 20.3.10(chokidar@4.0.3)
+ '@modelcontextprotocol/sdk': 1.24.0(zod@4.1.13)
+ '@schematics/angular': 20.3.13(chokidar@4.0.3)
'@yarnpkg/lockfile': 1.1.0
algoliasearch: 5.35.0
ini: 5.0.0
@@ -7491,21 +7513,22 @@ snapshots:
resolve: 1.22.10
semver: 7.7.2
yargs: 18.0.0
- zod: 3.25.76
+ zod: 4.1.13
transitivePeerDependencies:
+ - '@cfworker/json-schema'
- '@types/node'
- chokidar
- supports-color
- '@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)':
+ '@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)':
dependencies:
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
rxjs: 7.8.2
tslib: 2.8.1
- '@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)':
+ '@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)':
dependencies:
- '@angular/compiler': 20.3.12
+ '@angular/compiler': 20.3.15
'@babel/core': 7.28.3
'@jridgewell/sourcemap-codec': 1.5.5
chokidar: 4.0.3
@@ -7519,30 +7542,30 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@angular/compiler@20.3.12':
+ '@angular/compiler@20.3.15':
dependencies:
tslib: 2.8.1
- '@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)':
+ '@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)':
dependencies:
rxjs: 7.8.2
tslib: 2.8.1
optionalDependencies:
- '@angular/compiler': 20.3.12
+ '@angular/compiler': 20.3.15
zone.js: 0.15.1
- '@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)':
+ '@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
rxjs: 7.8.2
tslib: 2.8.1
- '@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)':
+ '@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)':
dependencies:
- '@angular/compiler': 20.3.12
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular/compiler': 20.3.15
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
'@babel/core': 7.28.3
'@types/babel__core': 7.20.5
tinyglobby: 0.2.15
@@ -7550,25 +7573,25 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@angular/platform-browser-dynamic@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))':
+ '@angular/platform-browser-dynamic@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/compiler': 20.3.12
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/compiler': 20.3.15
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
tslib: 2.8.1
- '@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))':
+ '@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
tslib: 2.8.1
- '@angular/router@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)':
+ '@angular/router@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
rxjs: 7.8.2
tslib: 2.8.1
@@ -7685,7 +7708,7 @@ snapshots:
'@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
- '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-member-expression-to-functions': 7.27.1
'@babel/helper-optimise-call-expression': 7.27.1
'@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.1)
@@ -7698,7 +7721,7 @@ snapshots:
'@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
- '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.3
regexpu-core: 6.2.0
semver: 6.3.1
@@ -7765,7 +7788,7 @@ snapshots:
'@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
- '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-wrap-function': 7.27.1
'@babel/traverse': 7.28.5
transitivePeerDependencies:
@@ -8201,7 +8224,7 @@ snapshots:
'@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.27.1)':
dependencies:
'@babel/core': 7.27.1
- '@babel/helper-annotate-as-pure': 7.27.1
+ '@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.1)
'@babel/helper-plugin-utils': 7.27.1
transitivePeerDependencies:
@@ -9258,9 +9281,10 @@ snapshots:
'@lmdb/lmdb-win32-x64@3.4.2':
optional: true
- '@modelcontextprotocol/sdk@1.17.3':
+ '@modelcontextprotocol/sdk@1.24.0(zod@4.1.13)':
dependencies:
- ajv: 6.12.6
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
content-type: 1.0.5
cors: 2.8.5
cross-spawn: 7.0.6
@@ -9268,10 +9292,11 @@ snapshots:
eventsource-parser: 3.0.6
express: 5.1.0
express-rate-limit: 7.5.1(express@5.1.0)
+ jose: 6.1.3
pkce-challenge: 5.0.0
raw-body: 3.0.1
- zod: 3.25.76
- zod-to-json-schema: 3.24.6(zod@3.25.76)
+ zod: 4.1.13
+ zod-to-json-schema: 3.25.0(zod@4.1.13)
transitivePeerDependencies:
- supports-color
@@ -9372,35 +9397,35 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
- '@ng-bootstrap/ng-bootstrap@19.0.1(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@popperjs/core@2.11.8)(rxjs@7.8.2)':
+ '@ng-bootstrap/ng-bootstrap@19.0.1(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@popperjs/core@2.11.8)(rxjs@7.8.2)':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/forms': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
- '@angular/localize': 20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/forms': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ '@angular/localize': 20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15)
'@popperjs/core': 2.11.8
rxjs: 7.8.2
tslib: 2.8.1
- '@ng-select/ng-select@20.7.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))':
+ '@ng-select/ng-select@20.7.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))':
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/forms': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/forms': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
tslib: 2.8.1
- '@ngneat/dirty-check-forms@3.0.3(8ff1ffec9c0eb3e42a8b58cc79f67aaa)':
+ '@ngneat/dirty-check-forms@3.0.3(218c118fbd72b8c5b4f5fd1fa1211ac5)':
dependencies:
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/forms': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
- '@angular/router': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/forms': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ '@angular/router': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
lodash-es: 4.17.21
rxjs: 7.8.2
tslib: 2.8.1
- '@ngtools/webpack@20.0.4(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.99.8(esbuild@0.25.5))':
+ '@ngtools/webpack@20.0.4(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.99.8(esbuild@0.25.5))':
dependencies:
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
typescript: 5.8.3
webpack: 5.99.8(esbuild@0.25.5)
@@ -9428,7 +9453,7 @@ snapshots:
'@npmcli/fs@4.0.0':
dependencies:
- semver: 7.7.2
+ semver: 7.7.3
'@npmcli/git@6.0.3':
dependencies:
@@ -9438,7 +9463,7 @@ snapshots:
npm-pick-manifest: 10.0.0
proc-log: 5.0.0
promise-retry: 2.0.1
- semver: 7.7.2
+ semver: 7.7.3
which: 5.0.0
'@npmcli/installed-package-contents@3.0.0':
@@ -9455,7 +9480,7 @@ snapshots:
hosted-git-info: 8.1.0
json-parse-even-better-errors: 4.0.0
proc-log: 5.0.0
- semver: 7.7.2
+ semver: 7.7.3
validate-npm-package-license: 3.0.4
'@npmcli/promise-spawn@8.0.3':
@@ -9731,10 +9756,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.52.3':
optional: true
- '@schematics/angular@20.3.10(chokidar@4.0.3)':
+ '@schematics/angular@20.3.13(chokidar@4.0.3)':
dependencies:
- '@angular-devkit/core': 20.3.10(chokidar@4.0.3)
- '@angular-devkit/schematics': 20.3.10(chokidar@4.0.3)
+ '@angular-devkit/core': 20.3.13(chokidar@4.0.3)
+ '@angular-devkit/schematics': 20.3.13(chokidar@4.0.3)
jsonc-parser: 3.3.1
transitivePeerDependencies:
- chokidar
@@ -10446,8 +10471,6 @@ snapshots:
base64-js@1.5.1:
optional: true
- baseline-browser-mapping@2.8.29: {}
-
baseline-browser-mapping@2.9.4: {}
batch@0.6.1: {}
@@ -10460,7 +10483,7 @@ snapshots:
domhandler: 5.0.3
htmlparser2: 10.0.0
picocolors: 1.1.1
- postcss: 8.5.3
+ postcss: 8.5.6
postcss-media-query-parser: 0.2.3
beasties@0.3.5:
@@ -10542,14 +10565,6 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.28.0:
- dependencies:
- baseline-browser-mapping: 2.8.29
- caniuse-lite: 1.0.30001755
- electron-to-chromium: 1.5.255
- node-releases: 2.0.27
- update-browserslist-db: 1.1.4(browserslist@4.28.0)
-
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.4
@@ -10611,8 +10626,6 @@ snapshots:
camelcase@6.3.0: {}
- caniuse-lite@1.0.30001755: {}
-
caniuse-lite@1.0.30001759: {}
canvas@3.0.0:
@@ -10807,7 +10820,7 @@ snapshots:
postcss-modules-scope: 3.2.1(postcss@8.5.3)
postcss-modules-values: 4.0.0(postcss@8.5.3)
postcss-value-parser: 4.2.0
- semver: 7.7.2
+ semver: 7.7.3
optionalDependencies:
webpack: 5.99.8(esbuild@0.25.5)
@@ -10955,8 +10968,6 @@ snapshots:
ee-first@1.1.1: {}
- electron-to-chromium@1.5.255: {}
-
electron-to-chromium@1.5.266: {}
emittery@0.13.1: {}
@@ -11354,10 +11365,6 @@ snapshots:
dependencies:
bser: 2.1.1
- fdir@6.5.0(picomatch@4.0.2):
- optionalDependencies:
- picomatch: 4.0.2
-
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
@@ -11810,11 +11817,11 @@ snapshots:
istanbul-lib-instrument@6.0.3:
dependencies:
- '@babel/core': 7.28.3
+ '@babel/core': 7.28.5
'@babel/parser': 7.28.5
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
- semver: 7.7.2
+ semver: 7.7.3
transitivePeerDependencies:
- supports-color
@@ -12102,11 +12109,11 @@ snapshots:
optionalDependencies:
jest-resolve: 30.2.0
- jest-preset-angular@14.6.0(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(canvas@3.0.0)(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jsdom@26.1.0(canvas@3.0.0))(typescript@5.8.3):
+ jest-preset-angular@14.6.0(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(canvas@3.0.0)(jest@30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3)))(jsdom@26.1.0(canvas@3.0.0))(typescript@5.8.3):
dependencies:
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser-dynamic': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser-dynamic': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))
bs-logger: 0.2.6
esbuild-wasm: 0.25.10
jest: 30.2.0(@types/node@24.10.1)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.8.3))
@@ -12128,12 +12135,12 @@ snapshots:
- supports-color
- utf-8-validate
- jest-preset-angular@15.0.3(138e950b6256ba9944139a8c5aad3bdf):
+ jest-preset-angular@15.0.3(e164a15bea80c603eb581d5724a352ec):
dependencies:
- '@angular/compiler-cli': 20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/platform-browser': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))
- '@angular/platform-browser-dynamic': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.12)(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))
+ '@angular/compiler-cli': 20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/platform-browser': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))
+ '@angular/platform-browser-dynamic': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.15)(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))
'@jest/environment-jsdom-abstract': 30.2.0(canvas@3.0.0)(jsdom@26.1.0(canvas@3.0.0))
bs-logger: 0.2.6
esbuild-wasm: 0.27.0
@@ -12333,6 +12340,8 @@ snapshots:
jiti@1.21.7: {}
+ jose@6.1.3: {}
+
js-tokens@4.0.0: {}
js-yaml@3.14.2:
@@ -12801,46 +12810,46 @@ snapshots:
pdfjs-dist: 4.8.69
tslib: 2.8.1
- ngx-bootstrap-icons@1.9.3(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)):
+ ngx-bootstrap-icons@1.9.3(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
tslib: 2.8.1
- ngx-color@10.1.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)):
+ ngx-color@10.1.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
'@ctrl/tinycolor': 4.2.0
material-colors: 1.2.6
tslib: 2.8.1
- ngx-cookie-service@20.1.1(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)):
+ ngx-cookie-service@20.1.1(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
tslib: 2.8.1
- ngx-device-detector@10.1.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)):
+ ngx-device-detector@10.1.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
tslib: 2.8.1
- ngx-ui-tour-core@15.0.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(rxjs@7.8.2):
+ ngx-ui-tour-core@15.0.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(rxjs@7.8.2):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@angular/router': 20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@angular/router': 20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
rxjs: 7.8.2
tslib: 2.8.1
- ngx-ui-tour-ng-bootstrap@17.0.1(1990d937b48b356c3a7b81a3382c7bae):
+ ngx-ui-tour-ng-bootstrap@17.0.1(43e0b240967005bbda3e3b71e72070f1):
dependencies:
- '@angular/common': 20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
- '@angular/core': 20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)
- '@ng-bootstrap/ng-bootstrap': 19.0.1(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.12(@angular/compiler-cli@20.3.12(@angular/compiler@20.3.12)(typescript@5.8.3))(@angular/compiler@20.3.12))(@popperjs/core@2.11.8)(rxjs@7.8.2)
- ngx-ui-tour-core: 15.0.0(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.12(@angular/common@20.3.14(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.12(@angular/compiler@20.3.12)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(rxjs@7.8.2)
+ '@angular/common': 20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)
+ '@angular/core': 20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)
+ '@ng-bootstrap/ng-bootstrap': 19.0.1(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(@angular/localize@20.3.15(@angular/compiler-cli@20.3.15(@angular/compiler@20.3.15)(typescript@5.8.3))(@angular/compiler@20.3.15))(@popperjs/core@2.11.8)(rxjs@7.8.2)
+ ngx-ui-tour-core: 15.0.0(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/router@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.15(@angular/common@20.3.15(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.15(@angular/compiler@20.3.15)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2))(rxjs@7.8.2)
tslib: 2.8.1
transitivePeerDependencies:
- '@angular/router'
@@ -12872,7 +12881,7 @@ snapshots:
make-fetch-happen: 14.0.3
nopt: 8.1.0
proc-log: 5.0.0
- semver: 7.7.2
+ semver: 7.7.3
tar: 7.5.2
tinyglobby: 0.2.15
which: 5.0.0
@@ -12897,7 +12906,7 @@ snapshots:
npm-install-checks@7.1.2:
dependencies:
- semver: 7.7.2
+ semver: 7.7.3
npm-normalize-package-bin@4.0.0: {}
@@ -12905,14 +12914,14 @@ snapshots:
dependencies:
hosted-git-info: 8.1.0
proc-log: 5.0.0
- semver: 7.7.2
+ semver: 7.7.3
validate-npm-package-name: 6.0.2
npm-package-arg@13.0.0:
dependencies:
hosted-git-info: 9.0.2
proc-log: 5.0.0
- semver: 7.7.2
+ semver: 7.7.3
validate-npm-package-name: 6.0.2
npm-packlist@10.0.3:
@@ -12925,7 +12934,7 @@ snapshots:
npm-install-checks: 7.1.2
npm-normalize-package-bin: 4.0.0
npm-package-arg: 12.0.2
- semver: 7.7.2
+ semver: 7.7.3
npm-registry-fetch@18.0.2:
dependencies:
@@ -13165,7 +13174,7 @@ snapshots:
cosmiconfig: 9.0.0(typescript@5.8.3)
jiti: 1.21.7
postcss: 8.5.3
- semver: 7.7.2
+ semver: 7.7.3
optionalDependencies:
webpack: 5.99.8(esbuild@0.25.5)
transitivePeerDependencies:
@@ -13962,8 +13971,8 @@ snapshots:
tinyglobby@0.2.13:
dependencies:
- fdir: 6.5.0(picomatch@4.0.2)
- picomatch: 4.0.2
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
tinyglobby@0.2.14:
dependencies:
@@ -14189,12 +14198,6 @@ snapshots:
'@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
'@unrs/resolver-binding-win32-x64-msvc': 1.11.1
- update-browserslist-db@1.1.4(browserslist@4.28.0):
- dependencies:
- browserslist: 4.28.0
- escalade: 3.2.0
- picocolors: 1.1.1
-
update-browserslist-db@1.2.2(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
@@ -14241,12 +14244,12 @@ snapshots:
vite@6.3.5(@types/node@24.10.1)(jiti@1.21.7)(less@4.3.0)(sass@1.88.0)(terser@5.39.1)(yaml@2.7.0):
dependencies:
- esbuild: 0.25.5
- fdir: 6.5.0(picomatch@4.0.2)
- picomatch: 4.0.2
- postcss: 8.5.3
- rollup: 4.40.2
- tinyglobby: 0.2.13
+ esbuild: 0.25.9
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.52.3
+ tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.1
fsevents: 2.3.3
@@ -14605,10 +14608,12 @@ snapshots:
yoctocolors-cjs@2.1.3: {}
- zod-to-json-schema@3.24.6(zod@3.25.76):
+ zod-to-json-schema@3.25.0(zod@4.1.13):
dependencies:
- zod: 3.25.76
+ zod: 4.1.13
zod@3.25.76: {}
+ zod@4.1.13: {}
+
zone.js@0.15.1: {}
diff --git a/src/documents/permissions.py b/src/documents/permissions.py
index cf6a9aa35..ac6d3f9ca 100644
--- a/src/documents/permissions.py
+++ b/src/documents/permissions.py
@@ -61,21 +61,22 @@ def get_groups_with_only_permission(obj, codename):
return Group.objects.filter(id__in=group_object_perm_group_ids).distinct()
-def set_permissions_for_object(permissions: list[str], object, *, merge: bool = False):
+def set_permissions_for_object(permissions: dict, object, *, merge: bool = False):
"""
- Set permissions for an object. The permissions are given as a list of strings
- in the format "action_modelname", e.g. "view_document".
+ Set permissions for an object. The permissions are given as a mapping of actions
+ to a dict of user / group id lists, e.g.
+ {"view": {"users": [1], "groups": [2]}, "change": {"users": [], "groups": []}}.
If merge is True, the permissions are merged with the existing permissions and
no users or groups are removed. If False, the permissions are set to exactly
the given list of users and groups.
"""
- for action in permissions:
+ for action, entry in permissions.items():
permission = f"{action}_{object.__class__.__name__.lower()}"
- if "users" in permissions[action]:
+ if "users" in entry:
# users
- users_to_add = User.objects.filter(id__in=permissions[action]["users"])
+ users_to_add = User.objects.filter(id__in=entry["users"])
users_to_remove = (
get_users_with_perms(
object,
@@ -85,12 +86,12 @@ def set_permissions_for_object(permissions: list[str], object, *, merge: bool =
if not merge
else User.objects.none()
)
- if len(users_to_add) > 0 and len(users_to_remove) > 0:
+ if users_to_add.exists() and users_to_remove.exists():
users_to_remove = users_to_remove.exclude(id__in=users_to_add)
- if len(users_to_remove) > 0:
+ if users_to_remove.exists():
for user in users_to_remove:
remove_perm(permission, user, object)
- if len(users_to_add) > 0:
+ if users_to_add.exists():
for user in users_to_add:
assign_perm(permission, user, object)
if action == "change":
@@ -100,9 +101,9 @@ def set_permissions_for_object(permissions: list[str], object, *, merge: bool =
user,
object,
)
- if "groups" in permissions[action]:
+ if "groups" in entry:
# groups
- groups_to_add = Group.objects.filter(id__in=permissions[action]["groups"])
+ groups_to_add = Group.objects.filter(id__in=entry["groups"])
groups_to_remove = (
get_groups_with_only_permission(
object,
@@ -111,12 +112,12 @@ def set_permissions_for_object(permissions: list[str], object, *, merge: bool =
if not merge
else Group.objects.none()
)
- if len(groups_to_add) > 0 and len(groups_to_remove) > 0:
+ if groups_to_add.exists() and groups_to_remove.exists():
groups_to_remove = groups_to_remove.exclude(id__in=groups_to_add)
- if len(groups_to_remove) > 0:
+ if groups_to_remove.exists():
for group in groups_to_remove:
remove_perm(permission, group, object)
- if len(groups_to_add) > 0:
+ if groups_to_add.exists():
for group in groups_to_add:
assign_perm(permission, group, object)
if action == "change":
diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py
index f04bb70da..3cb2b00af 100644
--- a/src/documents/serialisers.py
+++ b/src/documents/serialisers.py
@@ -585,6 +585,9 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
.select_related("owner")
.annotate(document_count=Count("documents", filter=filter_q)),
many=True,
+ user=self.user,
+ full_perms=self.full_perms,
+ all_fields=self.all_fields,
context=self.context,
)
return serializer.data
diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py
index 9803b3961..9e5b847d5 100644
--- a/src/documents/signals/handlers.py
+++ b/src/documents/signals/handlers.py
@@ -1,14 +1,10 @@
from __future__ import annotations
-import ipaddress
import logging
import shutil
-import socket
from pathlib import Path
from typing import TYPE_CHECKING
-from urllib.parse import urlparse
-import httpx
from celery import shared_task
from celery import states
from celery.signals import before_task_publish
@@ -27,7 +23,6 @@ from django.db.models import Q
from django.dispatch import receiver
from django.utils import timezone
from filelock import FileLock
-from guardian.shortcuts import remove_perm
from documents import matching
from documents.caching import clear_document_caches
@@ -36,13 +31,9 @@ from documents.data_models import ConsumableDocument
from documents.file_handling import create_source_path_directory
from documents.file_handling import delete_empty_directories
from documents.file_handling import generate_unique_filename
-from documents.mail import EmailAttachment
-from documents.mail import send_email
-from documents.models import Correspondent
from documents.models import CustomField
from documents.models import CustomFieldInstance
from documents.models import Document
-from documents.models import DocumentType
from documents.models import MatchingModel
from documents.models import PaperlessTask
from documents.models import SavedView
@@ -53,8 +44,14 @@ from documents.models import WorkflowAction
from documents.models import WorkflowRun
from documents.models import WorkflowTrigger
from documents.permissions import get_objects_for_user_owner_aware
-from documents.permissions import set_permissions_for_object
-from documents.templating.workflows import parse_w_workflow_placeholders
+from documents.workflows.actions import build_workflow_action_context
+from documents.workflows.actions import execute_email_action
+from documents.workflows.actions import execute_webhook_action
+from documents.workflows.mutations import apply_assignment_to_document
+from documents.workflows.mutations import apply_assignment_to_overrides
+from documents.workflows.mutations import apply_removal_to_document
+from documents.workflows.mutations import apply_removal_to_overrides
+from documents.workflows.utils import get_workflows_for_trigger
from paperless.config import AIConfig
if TYPE_CHECKING:
@@ -685,92 +682,6 @@ def run_workflows_updated(sender, document: Document, logging_group=None, **kwar
)
-def _is_public_ip(ip: str) -> bool:
- try:
- obj = ipaddress.ip_address(ip)
- return not (
- obj.is_private
- or obj.is_loopback
- or obj.is_link_local
- or obj.is_multicast
- or obj.is_unspecified
- )
- except ValueError: # pragma: no cover
- return False
-
-
-def _resolve_first_ip(host: str) -> str | None:
- try:
- info = socket.getaddrinfo(host, None)
- return info[0][4][0] if info else None
- except Exception: # pragma: no cover
- return None
-
-
-@shared_task(
- retry_backoff=True,
- autoretry_for=(httpx.HTTPStatusError,),
- max_retries=3,
- throws=(httpx.HTTPError,),
-)
-def send_webhook(
- url: str,
- data: str | dict,
- headers: dict,
- files: dict,
- *,
- as_json: bool = False,
-):
- p = urlparse(url)
- if p.scheme.lower() not in settings.WEBHOOKS_ALLOWED_SCHEMES or not p.hostname:
- logger.warning("Webhook blocked: invalid scheme/hostname")
- raise ValueError("Invalid URL scheme or hostname.")
-
- port = p.port or (443 if p.scheme == "https" else 80)
- if (
- len(settings.WEBHOOKS_ALLOWED_PORTS) > 0
- and port not in settings.WEBHOOKS_ALLOWED_PORTS
- ):
- logger.warning("Webhook blocked: port not permitted")
- raise ValueError("Destination port not permitted.")
-
- ip = _resolve_first_ip(p.hostname)
- if not ip or (
- not _is_public_ip(ip) and not settings.WEBHOOKS_ALLOW_INTERNAL_REQUESTS
- ):
- logger.warning("Webhook blocked: destination not allowed")
- raise ValueError("Destination host is not allowed.")
-
- try:
- post_args = {
- "url": url,
- "headers": {
- k: v for k, v in (headers or {}).items() if k.lower() != "host"
- },
- "files": files or None,
- "timeout": 5.0,
- "follow_redirects": False,
- }
- if as_json:
- post_args["json"] = data
- elif isinstance(data, dict):
- post_args["data"] = data
- else:
- post_args["content"] = data
-
- httpx.post(
- **post_args,
- ).raise_for_status()
- logger.info(
- f"Webhook sent to {url}",
- )
- except Exception as e:
- logger.error(
- f"Failed attempt sending webhook to {url}: {e}",
- )
- raise e
-
-
def run_workflows(
trigger_type: WorkflowTrigger.WorkflowTriggerType,
document: Document | ConsumableDocument,
@@ -779,572 +690,16 @@ def run_workflows(
overrides: DocumentMetadataOverrides | None = None,
original_file: Path | None = None,
) -> tuple[DocumentMetadataOverrides, str] | None:
- """Run workflows which match a Document (or ConsumableDocument) for a specific trigger type or a single workflow if given.
-
- Assignment or removal actions are either applied directly to the document or an overrides object. If an overrides
- object is provided, the function returns the object with the applied changes or None if no actions were applied and a string
- of messages for each action. If no overrides object is provided, the changes are applied directly to the document and the
- function returns None.
"""
+ Execute workflows matching a document for the given trigger. When `overrides` is provided
+ (consumption flow), actions mutate that object and the function returns `(overrides, messages)`.
+ Otherwise actions mutate the actual document and return nothing.
- def assignment_action():
- if action.assign_tags.exists():
- tag_ids_to_add: set[int] = set()
- for tag in action.assign_tags.all():
- tag_ids_to_add.add(tag.pk)
- tag_ids_to_add.update(int(pk) for pk in tag.get_ancestors_pks())
+ Attachments for email/webhook actions use `original_file` when given, otherwise fall back to
+ `document.source_path` (Document) or `document.original_file` (ConsumableDocument).
- if not use_overrides:
- doc_tag_ids[:] = list(set(doc_tag_ids) | tag_ids_to_add)
- else:
- if overrides.tag_ids is None:
- overrides.tag_ids = []
- overrides.tag_ids = list(set(overrides.tag_ids) | tag_ids_to_add)
-
- if action.assign_correspondent:
- if not use_overrides:
- document.correspondent = action.assign_correspondent
- else:
- overrides.correspondent_id = action.assign_correspondent.pk
-
- if action.assign_document_type:
- if not use_overrides:
- document.document_type = action.assign_document_type
- else:
- overrides.document_type_id = action.assign_document_type.pk
-
- if action.assign_storage_path:
- if not use_overrides:
- document.storage_path = action.assign_storage_path
- else:
- overrides.storage_path_id = action.assign_storage_path.pk
-
- if action.assign_owner:
- if not use_overrides:
- document.owner = action.assign_owner
- else:
- overrides.owner_id = action.assign_owner.pk
-
- if action.assign_title:
- if not use_overrides:
- try:
- document.title = parse_w_workflow_placeholders(
- action.assign_title,
- document.correspondent.name if document.correspondent else "",
- document.document_type.name if document.document_type else "",
- document.owner.username if document.owner else "",
- timezone.localtime(document.added),
- document.original_filename or "",
- document.filename or "",
- document.created,
- )
- except Exception:
- logger.exception(
- f"Error occurred parsing title assignment '{action.assign_title}', falling back to original",
- extra={"group": logging_group},
- )
- else:
- overrides.title = action.assign_title
-
- if any(
- [
- action.assign_view_users.exists(),
- action.assign_view_groups.exists(),
- action.assign_change_users.exists(),
- action.assign_change_groups.exists(),
- ],
- ):
- permissions = {
- "view": {
- "users": action.assign_view_users.values_list("id", flat=True),
- "groups": action.assign_view_groups.values_list("id", flat=True),
- },
- "change": {
- "users": action.assign_change_users.values_list("id", flat=True),
- "groups": action.assign_change_groups.values_list("id", flat=True),
- },
- }
- if not use_overrides:
- set_permissions_for_object(
- permissions=permissions,
- object=document,
- merge=True,
- )
- else:
- overrides.view_users = list(
- set(
- (overrides.view_users or [])
- + list(permissions["view"]["users"]),
- ),
- )
- overrides.view_groups = list(
- set(
- (overrides.view_groups or [])
- + list(permissions["view"]["groups"]),
- ),
- )
- overrides.change_users = list(
- set(
- (overrides.change_users or [])
- + list(permissions["change"]["users"]),
- ),
- )
- overrides.change_groups = list(
- set(
- (overrides.change_groups or [])
- + list(permissions["change"]["groups"]),
- ),
- )
-
- if action.assign_custom_fields.exists():
- if not use_overrides:
- for field in action.assign_custom_fields.all():
- value_field_name = CustomFieldInstance.get_value_field_name(
- data_type=field.data_type,
- )
- args = {
- value_field_name: action.assign_custom_fields_values.get(
- str(field.pk),
- None,
- ),
- }
- # for some reason update_or_create doesn't work here
- instance = CustomFieldInstance.objects.filter(
- field=field,
- document=document,
- ).first()
- if instance and args[value_field_name] is not None:
- setattr(instance, value_field_name, args[value_field_name])
- instance.save()
- elif not instance:
- CustomFieldInstance.objects.create(
- **args,
- field=field,
- document=document,
- )
- else:
- if overrides.custom_fields is None:
- overrides.custom_fields = {}
- overrides.custom_fields.update(
- {
- field.pk: action.assign_custom_fields_values.get(
- str(field.pk),
- None,
- )
- for field in action.assign_custom_fields.all()
- },
- )
-
- def removal_action():
- if action.remove_all_tags:
- if not use_overrides:
- doc_tag_ids.clear()
- else:
- overrides.tag_ids = None
- else:
- tag_ids_to_remove: set[int] = set()
- for tag in action.remove_tags.all():
- tag_ids_to_remove.add(tag.pk)
- tag_ids_to_remove.update(int(pk) for pk in tag.get_descendants_pks())
-
- if not use_overrides:
- doc_tag_ids[:] = [t for t in doc_tag_ids if t not in tag_ids_to_remove]
- elif overrides.tag_ids:
- overrides.tag_ids = [
- t for t in overrides.tag_ids if t not in tag_ids_to_remove
- ]
-
- if not use_overrides and (
- action.remove_all_correspondents
- or (
- document.correspondent
- and action.remove_correspondents.filter(
- pk=document.correspondent.pk,
- ).exists()
- )
- ):
- document.correspondent = None
- elif use_overrides and (
- action.remove_all_correspondents
- or (
- overrides.correspondent_id
- and action.remove_correspondents.filter(
- pk=overrides.correspondent_id,
- ).exists()
- )
- ):
- overrides.correspondent_id = None
-
- if not use_overrides and (
- action.remove_all_document_types
- or (
- document.document_type
- and action.remove_document_types.filter(
- pk=document.document_type.pk,
- ).exists()
- )
- ):
- document.document_type = None
- elif use_overrides and (
- action.remove_all_document_types
- or (
- overrides.document_type_id
- and action.remove_document_types.filter(
- pk=overrides.document_type_id,
- ).exists()
- )
- ):
- overrides.document_type_id = None
-
- if not use_overrides and (
- action.remove_all_storage_paths
- or (
- document.storage_path
- and action.remove_storage_paths.filter(
- pk=document.storage_path.pk,
- ).exists()
- )
- ):
- document.storage_path = None
- elif use_overrides and (
- action.remove_all_storage_paths
- or (
- overrides.storage_path_id
- and action.remove_storage_paths.filter(
- pk=overrides.storage_path_id,
- ).exists()
- )
- ):
- overrides.storage_path_id = None
-
- if not use_overrides and (
- action.remove_all_owners
- or (
- document.owner
- and action.remove_owners.filter(pk=document.owner.pk).exists()
- )
- ):
- document.owner = None
- elif use_overrides and (
- action.remove_all_owners
- or (
- overrides.owner_id
- and action.remove_owners.filter(pk=overrides.owner_id).exists()
- )
- ):
- overrides.owner_id = None
-
- if action.remove_all_permissions:
- if not use_overrides:
- permissions = {
- "view": {"users": [], "groups": []},
- "change": {"users": [], "groups": []},
- }
- set_permissions_for_object(
- permissions=permissions,
- object=document,
- merge=False,
- )
- else:
- overrides.view_users = None
- overrides.view_groups = None
- overrides.change_users = None
- overrides.change_groups = None
- elif any(
- [
- action.remove_view_users.exists(),
- action.remove_view_groups.exists(),
- action.remove_change_users.exists(),
- action.remove_change_groups.exists(),
- ],
- ):
- if not use_overrides:
- for user in action.remove_view_users.all():
- remove_perm("view_document", user, document)
- for user in action.remove_change_users.all():
- remove_perm("change_document", user, document)
- for group in action.remove_view_groups.all():
- remove_perm("view_document", group, document)
- for group in action.remove_change_groups.all():
- remove_perm("change_document", group, document)
- else:
- if overrides.view_users:
- for user in action.remove_view_users.filter(
- pk__in=overrides.view_users,
- ):
- overrides.view_users.remove(user.pk)
- if overrides.change_users:
- for user in action.remove_change_users.filter(
- pk__in=overrides.change_users,
- ):
- overrides.change_users.remove(user.pk)
- if overrides.view_groups:
- for group in action.remove_view_groups.filter(
- pk__in=overrides.view_groups,
- ):
- overrides.view_groups.remove(group.pk)
- if overrides.change_groups:
- for group in action.remove_change_groups.filter(
- pk__in=overrides.change_groups,
- ):
- overrides.change_groups.remove(group.pk)
-
- if action.remove_all_custom_fields:
- if not use_overrides:
- CustomFieldInstance.objects.filter(document=document).hard_delete()
- else:
- overrides.custom_fields = None
- elif action.remove_custom_fields.exists():
- if not use_overrides:
- CustomFieldInstance.objects.filter(
- field__in=action.remove_custom_fields.all(),
- document=document,
- ).hard_delete()
- elif overrides.custom_fields:
- for field in action.remove_custom_fields.filter(
- pk__in=overrides.custom_fields.keys(),
- ):
- overrides.custom_fields.pop(field.pk, None)
-
- def email_action():
- if not settings.EMAIL_ENABLED:
- logger.error(
- "Email backend has not been configured, cannot send email notifications",
- extra={"group": logging_group},
- )
- return
-
- if not use_overrides:
- title = document.title
- doc_url = (
- f"{settings.PAPERLESS_URL}{settings.BASE_URL}documents/{document.pk}/"
- )
- correspondent = (
- document.correspondent.name if document.correspondent else ""
- )
- document_type = (
- document.document_type.name if document.document_type else ""
- )
- owner_username = document.owner.username if document.owner else ""
- filename = document.original_filename or ""
- current_filename = document.filename or ""
- added = timezone.localtime(document.added)
- created = document.created
- else:
- title = overrides.title if overrides.title else str(document.original_file)
- doc_url = ""
- correspondent = (
- Correspondent.objects.filter(pk=overrides.correspondent_id).first()
- if overrides.correspondent_id
- else ""
- )
- document_type = (
- DocumentType.objects.filter(pk=overrides.document_type_id).first().name
- if overrides.document_type_id
- else ""
- )
- owner_username = (
- User.objects.filter(pk=overrides.owner_id).first().username
- if overrides.owner_id
- else ""
- )
- filename = document.original_file if document.original_file else ""
- current_filename = filename
- added = timezone.localtime(timezone.now())
- created = overrides.created
-
- subject = (
- parse_w_workflow_placeholders(
- action.email.subject,
- correspondent,
- document_type,
- owner_username,
- added,
- filename,
- current_filename,
- created,
- title,
- doc_url,
- )
- if action.email.subject
- else ""
- )
- body = (
- parse_w_workflow_placeholders(
- action.email.body,
- correspondent,
- document_type,
- owner_username,
- added,
- filename,
- current_filename,
- created,
- title,
- doc_url,
- )
- if action.email.body
- else ""
- )
- try:
- attachments: list[EmailAttachment] = []
- if action.email.include_document:
- attachment: EmailAttachment | None = None
- if trigger_type in [
- WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED,
- WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
- ] and isinstance(document, Document):
- friendly_name = (
- Path(current_filename).name
- if current_filename
- else document.source_path.name
- )
- attachment = EmailAttachment(
- path=document.source_path,
- mime_type=document.mime_type,
- friendly_name=friendly_name,
- )
- elif original_file:
- friendly_name = (
- Path(current_filename).name
- if current_filename
- else original_file.name
- )
- attachment = EmailAttachment(
- path=original_file,
- mime_type=document.mime_type,
- friendly_name=friendly_name,
- )
- if attachment:
- attachments = [attachment]
- n_messages = send_email(
- subject=subject,
- body=body,
- to=action.email.to.split(","),
- attachments=attachments,
- )
- logger.debug(
- f"Sent {n_messages} notification email(s) to {action.email.to}",
- extra={"group": logging_group},
- )
- except Exception as e:
- logger.exception(
- f"Error occurred sending notification email: {e}",
- extra={"group": logging_group},
- )
-
- def webhook_action():
- if not use_overrides:
- title = document.title
- doc_url = (
- f"{settings.PAPERLESS_URL}{settings.BASE_URL}documents/{document.pk}/"
- )
- correspondent = (
- document.correspondent.name if document.correspondent else ""
- )
- document_type = (
- document.document_type.name if document.document_type else ""
- )
- owner_username = document.owner.username if document.owner else ""
- filename = document.original_filename or ""
- current_filename = document.filename or ""
- added = timezone.localtime(document.added)
- created = document.created
- else:
- title = overrides.title if overrides.title else str(document.original_file)
- doc_url = ""
- correspondent = (
- Correspondent.objects.filter(pk=overrides.correspondent_id).first()
- if overrides.correspondent_id
- else ""
- )
- document_type = (
- DocumentType.objects.filter(pk=overrides.document_type_id).first().name
- if overrides.document_type_id
- else ""
- )
- owner_username = (
- User.objects.filter(pk=overrides.owner_id).first().username
- if overrides.owner_id
- else ""
- )
- filename = document.original_file if document.original_file else ""
- current_filename = filename
- added = timezone.localtime(timezone.now())
- created = overrides.created
-
- try:
- data = {}
- if action.webhook.use_params:
- if action.webhook.params:
- try:
- for key, value in action.webhook.params.items():
- data[key] = parse_w_workflow_placeholders(
- value,
- correspondent,
- document_type,
- owner_username,
- added,
- filename,
- current_filename,
- created,
- title,
- doc_url,
- )
- except Exception as e:
- logger.error(
- f"Error occurred parsing webhook params: {e}",
- extra={"group": logging_group},
- )
- elif action.webhook.body:
- data = parse_w_workflow_placeholders(
- action.webhook.body,
- correspondent,
- document_type,
- owner_username,
- added,
- filename,
- current_filename,
- created,
- title,
- doc_url,
- )
- headers = {}
- if action.webhook.headers:
- try:
- headers = {
- str(k): str(v) for k, v in action.webhook.headers.items()
- }
- except Exception as e:
- logger.error(
- f"Error occurred parsing webhook headers: {e}",
- extra={"group": logging_group},
- )
- files = None
- if action.webhook.include_document:
- with original_file.open("rb") as f:
- files = {
- "file": (
- filename,
- f.read(),
- document.mime_type,
- ),
- }
- send_webhook.delay(
- url=action.webhook.url,
- data=data,
- headers=headers,
- files=files,
- as_json=action.webhook.as_json,
- )
- logger.debug(
- f"Webhook to {action.webhook.url} queued",
- extra={"group": logging_group},
- )
- except Exception as e:
- logger.exception(
- f"Error occurred sending webhook: {e}",
- extra={"group": logging_group},
- )
+ Passing `workflow_to_run` skips the workflow query (currently only used by scheduled runs).
+ """
use_overrides = overrides is not None
if original_file is None:
@@ -1353,30 +708,7 @@ def run_workflows(
)
messages = []
- workflows = (
- (
- Workflow.objects.filter(enabled=True, triggers__type=trigger_type)
- .prefetch_related(
- "actions",
- "actions__assign_view_users",
- "actions__assign_view_groups",
- "actions__assign_change_users",
- "actions__assign_change_groups",
- "actions__assign_custom_fields",
- "actions__remove_tags",
- "actions__remove_correspondents",
- "actions__remove_document_types",
- "actions__remove_storage_paths",
- "actions__remove_custom_fields",
- "actions__remove_owners",
- "triggers",
- )
- .order_by("order")
- .distinct()
- )
- if workflow_to_run is None
- else [workflow_to_run]
- )
+ workflows = get_workflows_for_trigger(trigger_type, workflow_to_run)
for workflow in workflows:
if not use_overrides:
@@ -1396,13 +728,39 @@ def run_workflows(
messages.append(message)
if action.type == WorkflowAction.WorkflowActionType.ASSIGNMENT:
- assignment_action()
+ if use_overrides and overrides:
+ apply_assignment_to_overrides(action, overrides)
+ else:
+ apply_assignment_to_document(
+ action,
+ document,
+ doc_tag_ids,
+ logging_group,
+ )
elif action.type == WorkflowAction.WorkflowActionType.REMOVAL:
- removal_action()
+ if use_overrides and overrides:
+ apply_removal_to_overrides(action, overrides)
+ else:
+ apply_removal_to_document(action, document, doc_tag_ids)
elif action.type == WorkflowAction.WorkflowActionType.EMAIL:
- email_action()
+ context = build_workflow_action_context(document, overrides)
+ execute_email_action(
+ action,
+ document,
+ context,
+ logging_group,
+ original_file,
+ trigger_type,
+ )
elif action.type == WorkflowAction.WorkflowActionType.WEBHOOK:
- webhook_action()
+ context = build_workflow_action_context(document, overrides)
+ execute_webhook_action(
+ action,
+ document,
+ context,
+ logging_group,
+ original_file,
+ )
if not use_overrides:
# limit title to 128 characters
diff --git a/src/documents/tasks.py b/src/documents/tasks.py
index a53e80c78..6d0e2f0c0 100644
--- a/src/documents/tasks.py
+++ b/src/documents/tasks.py
@@ -41,7 +41,6 @@ from documents.models import DocumentType
from documents.models import PaperlessTask
from documents.models import StoragePath
from documents.models import Tag
-from documents.models import Workflow
from documents.models import WorkflowRun
from documents.models import WorkflowTrigger
from documents.parsers import DocumentParser
@@ -54,6 +53,7 @@ from documents.sanity_checker import SanityCheckFailedException
from documents.signals import document_updated
from documents.signals.handlers import cleanup_document_deletion
from documents.signals.handlers import run_workflows
+from documents.workflows.utils import get_workflows_for_trigger
from paperless.config import AIConfig
from paperless_ai.indexing import llm_index_add_or_update_document
from paperless_ai.indexing import llm_index_remove_document
@@ -415,13 +415,8 @@ def check_scheduled_workflows():
Once a document satisfies this condition, and recurring/non-recurring constraints are met, the workflow is run.
"""
- scheduled_workflows: list[Workflow] = (
- Workflow.objects.filter(
- triggers__type=WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
- enabled=True,
- )
- .distinct()
- .prefetch_related("triggers")
+ scheduled_workflows = get_workflows_for_trigger(
+ WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
)
if scheduled_workflows.count() > 0:
logger.debug(f"Checking {len(scheduled_workflows)} scheduled workflows")
diff --git a/src/documents/tests/test_api_search.py b/src/documents/tests/test_api_search.py
index 5a2fc9b52..191381721 100644
--- a/src/documents/tests/test_api_search.py
+++ b/src/documents/tests/test_api_search.py
@@ -1289,7 +1289,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
content_type__app_label="admin",
),
)
- set_permissions([4, 5], set_permissions=[], owner=user2, merge=False)
+ set_permissions([4, 5], set_permissions={}, owner=user2, merge=False)
with index.open_index_writer() as writer:
index.update_document(writer, d1)
diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py
index 6438e4b10..e606bc5a0 100644
--- a/src/documents/tests/test_workflows.py
+++ b/src/documents/tests/test_workflows.py
@@ -26,7 +26,7 @@ from rest_framework.test import APITestCase
from documents.file_handling import create_source_path_directory
from documents.file_handling import generate_unique_filename
from documents.signals.handlers import run_workflows
-from documents.signals.handlers import send_webhook
+from documents.workflows.webhooks import send_webhook
if TYPE_CHECKING:
from django.db.models import QuerySet
@@ -2858,7 +2858,7 @@ class TestWorkflows(
mock_email_send.return_value = 1
- with self.assertNoLogs("paperless.handlers", level="ERROR"):
+ with self.assertNoLogs("paperless.workflows", level="ERROR"):
run_workflows(
WorkflowTrigger.WorkflowTriggerType.CONSUMPTION,
consumable_document,
@@ -3096,7 +3096,7 @@ class TestWorkflows(
original_filename="sample.pdf",
)
- with self.assertLogs("paperless.handlers", level="ERROR") as cm:
+ with self.assertLogs("paperless.workflows.actions", level="ERROR") as cm:
run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc)
expected_str = "Email backend has not been configured"
@@ -3144,7 +3144,7 @@ class TestWorkflows(
original_filename="sample.pdf",
)
- with self.assertLogs("paperless.handlers", level="ERROR") as cm:
+ with self.assertLogs("paperless.workflows", level="ERROR") as cm:
run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc)
expected_str = "Error occurred sending email"
@@ -3215,7 +3215,7 @@ class TestWorkflows(
PAPERLESS_FORCE_SCRIPT_NAME="/paperless",
BASE_URL="/paperless/",
)
- @mock.patch("documents.signals.handlers.send_webhook.delay")
+ @mock.patch("documents.workflows.webhooks.send_webhook.delay")
def test_workflow_webhook_action_body(self, mock_post):
"""
GIVEN:
@@ -3274,7 +3274,7 @@ class TestWorkflows(
@override_settings(
PAPERLESS_URL="http://localhost:8000",
)
- @mock.patch("documents.signals.handlers.send_webhook.delay")
+ @mock.patch("documents.workflows.webhooks.send_webhook.delay")
def test_workflow_webhook_action_w_files(self, mock_post):
"""
GIVEN:
@@ -3377,7 +3377,7 @@ class TestWorkflows(
)
# fails because no file
- with self.assertLogs("paperless.handlers", level="ERROR") as cm:
+ with self.assertLogs("paperless.workflows", level="ERROR") as cm:
run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc)
expected_str = "Error occurred sending webhook"
@@ -3420,7 +3420,7 @@ class TestWorkflows(
original_filename="sample.pdf",
)
- with self.assertLogs("paperless.handlers", level="ERROR") as cm:
+ with self.assertLogs("paperless.workflows", level="ERROR") as cm:
run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc)
expected_str = "Error occurred parsing webhook params"
@@ -3436,7 +3436,7 @@ class TestWorkflows(
raise_for_status=mock.Mock(),
)
- with self.assertLogs("paperless.handlers") as cm:
+ with self.assertLogs("paperless.workflows") as cm:
send_webhook(
url="http://paperless-ngx.com",
data="Test message",
@@ -3482,7 +3482,7 @@ class TestWorkflows(
),
)
- with self.assertLogs("paperless.handlers") as cm:
+ with self.assertLogs("paperless.workflows") as cm:
with self.assertRaises(HTTPStatusError):
send_webhook(
url="http://paperless-ngx.com",
@@ -3498,7 +3498,7 @@ class TestWorkflows(
)
self.assertIn(expected_str, cm.output[0])
- @mock.patch("documents.signals.handlers.send_webhook.delay")
+ @mock.patch("documents.workflows.webhooks.send_webhook.delay")
def test_workflow_webhook_action_consumption(self, mock_post):
"""
GIVEN:
diff --git a/src/documents/workflows/__init__.py b/src/documents/workflows/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/documents/workflows/actions.py b/src/documents/workflows/actions.py
new file mode 100644
index 000000000..040cbc127
--- /dev/null
+++ b/src/documents/workflows/actions.py
@@ -0,0 +1,261 @@
+import logging
+from pathlib import Path
+
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.utils import timezone
+
+from documents.data_models import ConsumableDocument
+from documents.data_models import DocumentMetadataOverrides
+from documents.mail import EmailAttachment
+from documents.mail import send_email
+from documents.models import Correspondent
+from documents.models import Document
+from documents.models import DocumentType
+from documents.models import WorkflowAction
+from documents.models import WorkflowTrigger
+from documents.templating.workflows import parse_w_workflow_placeholders
+from documents.workflows.webhooks import send_webhook
+
+logger = logging.getLogger("paperless.workflows.actions")
+
+
+def build_workflow_action_context(
+ document: Document | ConsumableDocument,
+ overrides: DocumentMetadataOverrides | None,
+) -> dict:
+ """
+ Build context dictionary for workflow action placeholder parsing.
+ """
+ use_overrides = overrides is not None
+
+ if not use_overrides:
+ return {
+ "title": document.title,
+ "doc_url": f"{settings.PAPERLESS_URL}{settings.BASE_URL}documents/{document.pk}/",
+ "correspondent": document.correspondent.name
+ if document.correspondent
+ else "",
+ "document_type": document.document_type.name
+ if document.document_type
+ else "",
+ "owner_username": document.owner.username if document.owner else "",
+ "filename": document.original_filename or "",
+ "current_filename": document.filename or "",
+ "added": timezone.localtime(document.added),
+ "created": document.created,
+ }
+
+ correspondent_obj = (
+ Correspondent.objects.filter(pk=overrides.correspondent_id).first()
+ if overrides and overrides.correspondent_id
+ else None
+ )
+ document_type_obj = (
+ DocumentType.objects.filter(pk=overrides.document_type_id).first()
+ if overrides and overrides.document_type_id
+ else None
+ )
+ owner_obj = (
+ User.objects.filter(pk=overrides.owner_id).first()
+ if overrides and overrides.owner_id
+ else None
+ )
+
+ filename = document.original_file if document.original_file else ""
+ return {
+ "title": overrides.title
+ if overrides and overrides.title
+ else str(document.original_file),
+ "doc_url": "",
+ "correspondent": correspondent_obj.name if correspondent_obj else "",
+ "document_type": document_type_obj.name if document_type_obj else "",
+ "owner_username": owner_obj.username if owner_obj else "",
+ "filename": filename,
+ "current_filename": filename,
+ "added": timezone.localtime(timezone.now()),
+ "created": overrides.created if overrides else None,
+ }
+
+
+def execute_email_action(
+ action: WorkflowAction,
+ document: Document | ConsumableDocument,
+ context: dict,
+ logging_group,
+ original_file: Path,
+ trigger_type: WorkflowTrigger.WorkflowTriggerType,
+) -> None:
+ """
+ Execute an email action for a workflow.
+ """
+
+ if not settings.EMAIL_ENABLED:
+ logger.error(
+ "Email backend has not been configured, cannot send email notifications",
+ extra={"group": logging_group},
+ )
+ return
+
+ subject = (
+ parse_w_workflow_placeholders(
+ action.email.subject,
+ context["correspondent"],
+ context["document_type"],
+ context["owner_username"],
+ context["added"],
+ context["filename"],
+ context["current_filename"],
+ context["created"],
+ context["title"],
+ context["doc_url"],
+ )
+ if action.email.subject
+ else ""
+ )
+ body = (
+ parse_w_workflow_placeholders(
+ action.email.body,
+ context["correspondent"],
+ context["document_type"],
+ context["owner_username"],
+ context["added"],
+ context["filename"],
+ context["current_filename"],
+ context["created"],
+ context["title"],
+ context["doc_url"],
+ )
+ if action.email.body
+ else ""
+ )
+
+ try:
+ attachments: list[EmailAttachment] = []
+ if action.email.include_document:
+ attachment: EmailAttachment | None = None
+ if trigger_type in [
+ WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED,
+ WorkflowTrigger.WorkflowTriggerType.SCHEDULED,
+ ] and isinstance(document, Document):
+ friendly_name = (
+ Path(context["current_filename"]).name
+ if context["current_filename"]
+ else document.source_path.name
+ )
+ attachment = EmailAttachment(
+ path=document.source_path,
+ mime_type=document.mime_type,
+ friendly_name=friendly_name,
+ )
+ elif original_file:
+ friendly_name = (
+ Path(context["current_filename"]).name
+ if context["current_filename"]
+ else original_file.name
+ )
+ attachment = EmailAttachment(
+ path=original_file,
+ mime_type=document.mime_type,
+ friendly_name=friendly_name,
+ )
+ if attachment:
+ attachments = [attachment]
+
+ n_messages = send_email(
+ subject=subject,
+ body=body,
+ to=action.email.to.split(","),
+ attachments=attachments,
+ )
+ logger.debug(
+ f"Sent {n_messages} notification email(s) to {action.email.to}",
+ extra={"group": logging_group},
+ )
+ except Exception as e:
+ logger.exception(
+ f"Error occurred sending notification email: {e}",
+ extra={"group": logging_group},
+ )
+
+
+def execute_webhook_action(
+ action: WorkflowAction,
+ document: Document | ConsumableDocument,
+ context: dict,
+ logging_group,
+ original_file: Path,
+):
+ try:
+ data = {}
+ if action.webhook.use_params:
+ if action.webhook.params:
+ try:
+ for key, value in action.webhook.params.items():
+ data[key] = parse_w_workflow_placeholders(
+ value,
+ context["correspondent"],
+ context["document_type"],
+ context["owner_username"],
+ context["added"],
+ context["filename"],
+ context["current_filename"],
+ context["created"],
+ context["title"],
+ context["doc_url"],
+ )
+ except Exception as e:
+ logger.error(
+ f"Error occurred parsing webhook params: {e}",
+ extra={"group": logging_group},
+ )
+ elif action.webhook.body:
+ data = parse_w_workflow_placeholders(
+ action.webhook.body,
+ context["correspondent"],
+ context["document_type"],
+ context["owner_username"],
+ context["added"],
+ context["filename"],
+ context["current_filename"],
+ context["created"],
+ context["title"],
+ context["doc_url"],
+ )
+ headers = {}
+ if action.webhook.headers:
+ try:
+ headers = {str(k): str(v) for k, v in action.webhook.headers.items()}
+ except Exception as e:
+ logger.error(
+ f"Error occurred parsing webhook headers: {e}",
+ extra={"group": logging_group},
+ )
+ files = None
+ if action.webhook.include_document:
+ with original_file.open("rb") as f:
+ files = {
+ "file": (
+ str(context["filename"])
+ if context["filename"]
+ else original_file.name,
+ f.read(),
+ document.mime_type,
+ ),
+ }
+ send_webhook.delay(
+ url=action.webhook.url,
+ data=data,
+ headers=headers,
+ files=files,
+ as_json=action.webhook.as_json,
+ )
+ logger.debug(
+ f"Webhook to {action.webhook.url} queued",
+ extra={"group": logging_group},
+ )
+ except Exception as e:
+ logger.exception(
+ f"Error occurred sending webhook: {e}",
+ extra={"group": logging_group},
+ )
diff --git a/src/documents/workflows/mutations.py b/src/documents/workflows/mutations.py
new file mode 100644
index 000000000..ef85dba0f
--- /dev/null
+++ b/src/documents/workflows/mutations.py
@@ -0,0 +1,357 @@
+import logging
+
+from django.utils import timezone
+from guardian.shortcuts import remove_perm
+
+from documents.data_models import DocumentMetadataOverrides
+from documents.models import CustomFieldInstance
+from documents.models import Document
+from documents.models import WorkflowAction
+from documents.permissions import set_permissions_for_object
+from documents.templating.workflows import parse_w_workflow_placeholders
+
+logger = logging.getLogger("paperless.workflows.mutations")
+
+
+def apply_assignment_to_document(
+ action: WorkflowAction,
+ document: Document,
+ doc_tag_ids: list[int],
+ logging_group,
+):
+ """
+ Apply assignment actions to a Document instance.
+
+ action: WorkflowAction, annotated with 'has_assign_*' boolean fields
+ """
+ if action.has_assign_tags:
+ tag_ids_to_add: set[int] = set()
+ for tag in action.assign_tags.all():
+ tag_ids_to_add.add(tag.pk)
+ tag_ids_to_add.update(int(pk) for pk in tag.get_ancestors_pks())
+
+ doc_tag_ids[:] = list(set(doc_tag_ids) | tag_ids_to_add)
+
+ if action.assign_correspondent:
+ document.correspondent = action.assign_correspondent
+
+ if action.assign_document_type:
+ document.document_type = action.assign_document_type
+
+ if action.assign_storage_path:
+ document.storage_path = action.assign_storage_path
+
+ if action.assign_owner:
+ document.owner = action.assign_owner
+
+ if action.assign_title:
+ try:
+ document.title = parse_w_workflow_placeholders(
+ action.assign_title,
+ document.correspondent.name if document.correspondent else "",
+ document.document_type.name if document.document_type else "",
+ document.owner.username if document.owner else "",
+ timezone.localtime(document.added),
+ document.original_filename or "",
+ document.filename or "",
+ document.created,
+ )
+ except Exception: # pragma: no cover
+ logger.exception(
+ f"Error occurred parsing title assignment '{action.assign_title}', falling back to original",
+ extra={"group": logging_group},
+ )
+
+ if any(
+ [
+ action.has_assign_view_users,
+ action.has_assign_view_groups,
+ action.has_assign_change_users,
+ action.has_assign_change_groups,
+ ],
+ ):
+ permissions = {
+ "view": {
+ "users": action.assign_view_users.values_list("id", flat=True),
+ "groups": action.assign_view_groups.values_list("id", flat=True),
+ },
+ "change": {
+ "users": action.assign_change_users.values_list("id", flat=True),
+ "groups": action.assign_change_groups.values_list("id", flat=True),
+ },
+ }
+ set_permissions_for_object(
+ permissions=permissions,
+ object=document,
+ merge=True,
+ )
+
+ if action.has_assign_custom_fields:
+ for field in action.assign_custom_fields.all():
+ value_field_name = CustomFieldInstance.get_value_field_name(
+ data_type=field.data_type,
+ )
+ args = {
+ value_field_name: action.assign_custom_fields_values.get(
+ str(field.pk),
+ None,
+ ),
+ }
+ # for some reason update_or_create doesn't work here
+ instance = CustomFieldInstance.objects.filter(
+ field=field,
+ document=document,
+ ).first()
+ if instance and args[value_field_name] is not None:
+ setattr(instance, value_field_name, args[value_field_name])
+ instance.save()
+ elif not instance:
+ CustomFieldInstance.objects.create(
+ **args,
+ field=field,
+ document=document,
+ )
+
+
+def apply_assignment_to_overrides(
+ action: WorkflowAction,
+ overrides: DocumentMetadataOverrides,
+):
+ """
+ Apply assignment actions to DocumentMetadataOverrides.
+
+ action: WorkflowAction, annotated with 'has_assign_*' boolean fields
+ """
+ if action.has_assign_tags:
+ if overrides.tag_ids is None:
+ overrides.tag_ids = []
+ tag_ids_to_add: set[int] = set()
+ for tag in action.assign_tags.all():
+ tag_ids_to_add.add(tag.pk)
+ tag_ids_to_add.update(int(pk) for pk in tag.get_ancestors_pks())
+
+ overrides.tag_ids = list(set(overrides.tag_ids) | tag_ids_to_add)
+
+ if action.assign_correspondent:
+ overrides.correspondent_id = action.assign_correspondent.pk
+
+ if action.assign_document_type:
+ overrides.document_type_id = action.assign_document_type.pk
+
+ if action.assign_storage_path:
+ overrides.storage_path_id = action.assign_storage_path.pk
+
+ if action.assign_owner:
+ overrides.owner_id = action.assign_owner.pk
+
+ if action.assign_title:
+ overrides.title = action.assign_title
+
+ if any(
+ [
+ action.has_assign_view_users,
+ action.has_assign_view_groups,
+ action.has_assign_change_users,
+ action.has_assign_change_groups,
+ ],
+ ):
+ overrides.view_users = list(
+ set(
+ (overrides.view_users or [])
+ + list(action.assign_view_users.values_list("id", flat=True)),
+ ),
+ )
+ overrides.view_groups = list(
+ set(
+ (overrides.view_groups or [])
+ + list(action.assign_view_groups.values_list("id", flat=True)),
+ ),
+ )
+ overrides.change_users = list(
+ set(
+ (overrides.change_users or [])
+ + list(action.assign_change_users.values_list("id", flat=True)),
+ ),
+ )
+ overrides.change_groups = list(
+ set(
+ (overrides.change_groups or [])
+ + list(action.assign_change_groups.values_list("id", flat=True)),
+ ),
+ )
+
+ if action.has_assign_custom_fields:
+ if overrides.custom_fields is None:
+ overrides.custom_fields = {}
+ overrides.custom_fields.update(
+ {
+ field.pk: action.assign_custom_fields_values.get(
+ str(field.pk),
+ None,
+ )
+ for field in action.assign_custom_fields.all()
+ },
+ )
+
+
+def apply_removal_to_document(
+ action: WorkflowAction,
+ document: Document,
+ doc_tag_ids: list[int],
+):
+ """
+ Apply removal actions to a Document instance.
+
+ action: WorkflowAction, annotated with 'has_remove_*' boolean fields
+ """
+
+ if action.remove_all_tags:
+ doc_tag_ids.clear()
+ else:
+ tag_ids_to_remove: set[int] = set()
+ for tag in action.remove_tags.all():
+ tag_ids_to_remove.add(tag.pk)
+ tag_ids_to_remove.update(int(pk) for pk in tag.get_descendants_pks())
+
+ doc_tag_ids[:] = [t for t in doc_tag_ids if t not in tag_ids_to_remove]
+
+ if action.remove_all_correspondents or (
+ document.correspondent
+ and action.remove_correspondents.filter(pk=document.correspondent.pk).exists()
+ ):
+ document.correspondent = None
+
+ if action.remove_all_document_types or (
+ document.document_type
+ and action.remove_document_types.filter(pk=document.document_type.pk).exists()
+ ):
+ document.document_type = None
+
+ if action.remove_all_storage_paths or (
+ document.storage_path
+ and action.remove_storage_paths.filter(pk=document.storage_path.pk).exists()
+ ):
+ document.storage_path = None
+
+ if action.remove_all_owners or (
+ document.owner and action.remove_owners.filter(pk=document.owner.pk).exists()
+ ):
+ document.owner = None
+
+ if action.remove_all_permissions:
+ permissions = {
+ "view": {"users": [], "groups": []},
+ "change": {"users": [], "groups": []},
+ }
+ set_permissions_for_object(
+ permissions=permissions,
+ object=document,
+ merge=False,
+ )
+
+ if any(
+ [
+ action.has_remove_view_users,
+ action.has_remove_view_groups,
+ action.has_remove_change_users,
+ action.has_remove_change_groups,
+ ],
+ ):
+ for user in action.remove_view_users.all():
+ remove_perm("view_document", user, document)
+ for user in action.remove_change_users.all():
+ remove_perm("change_document", user, document)
+ for group in action.remove_view_groups.all():
+ remove_perm("view_document", group, document)
+ for group in action.remove_change_groups.all():
+ remove_perm("change_document", group, document)
+
+ if action.remove_all_custom_fields:
+ CustomFieldInstance.objects.filter(document=document).hard_delete()
+ elif action.has_remove_custom_fields:
+ CustomFieldInstance.objects.filter(
+ field__in=action.remove_custom_fields.all(),
+ document=document,
+ ).hard_delete()
+
+
+def apply_removal_to_overrides(
+ action: WorkflowAction,
+ overrides: DocumentMetadataOverrides,
+):
+ """
+ Apply removal actions to DocumentMetadataOverrides.
+
+ action: WorkflowAction, annotated with 'has_remove_*' boolean fields
+ """
+ if action.remove_all_tags:
+ overrides.tag_ids = None
+ elif overrides.tag_ids:
+ tag_ids_to_remove: set[int] = set()
+ for tag in action.remove_tags.all():
+ tag_ids_to_remove.add(tag.pk)
+ tag_ids_to_remove.update(int(pk) for pk in tag.get_descendants_pks())
+
+ overrides.tag_ids = [t for t in overrides.tag_ids if t not in tag_ids_to_remove]
+
+ if action.remove_all_correspondents or (
+ overrides.correspondent_id
+ and action.remove_correspondents.filter(pk=overrides.correspondent_id).exists()
+ ):
+ overrides.correspondent_id = None
+
+ if action.remove_all_document_types or (
+ overrides.document_type_id
+ and action.remove_document_types.filter(pk=overrides.document_type_id).exists()
+ ):
+ overrides.document_type_id = None
+
+ if action.remove_all_storage_paths or (
+ overrides.storage_path_id
+ and action.remove_storage_paths.filter(pk=overrides.storage_path_id).exists()
+ ):
+ overrides.storage_path_id = None
+
+ if action.remove_all_owners or (
+ overrides.owner_id
+ and action.remove_owners.filter(pk=overrides.owner_id).exists()
+ ):
+ overrides.owner_id = None
+
+ if action.remove_all_permissions:
+ overrides.view_users = None
+ overrides.view_groups = None
+ overrides.change_users = None
+ overrides.change_groups = None
+ elif any(
+ [
+ action.has_remove_view_users,
+ action.has_remove_view_groups,
+ action.has_remove_change_users,
+ action.has_remove_change_groups,
+ ],
+ ):
+ if overrides.view_users:
+ for user in action.remove_view_users.filter(pk__in=overrides.view_users):
+ overrides.view_users.remove(user.pk)
+ if overrides.change_users:
+ for user in action.remove_change_users.filter(
+ pk__in=overrides.change_users,
+ ):
+ overrides.change_users.remove(user.pk)
+ if overrides.view_groups:
+ for group in action.remove_view_groups.filter(pk__in=overrides.view_groups):
+ overrides.view_groups.remove(group.pk)
+ if overrides.change_groups:
+ for group in action.remove_change_groups.filter(
+ pk__in=overrides.change_groups,
+ ):
+ overrides.change_groups.remove(group.pk)
+
+ if action.remove_all_custom_fields:
+ overrides.custom_fields = None
+ elif action.has_remove_custom_fields and overrides.custom_fields:
+ for field in action.remove_custom_fields.filter(
+ pk__in=overrides.custom_fields.keys(),
+ ):
+ overrides.custom_fields.pop(field.pk, None)
diff --git a/src/documents/workflows/utils.py b/src/documents/workflows/utils.py
new file mode 100644
index 000000000..553622252
--- /dev/null
+++ b/src/documents/workflows/utils.py
@@ -0,0 +1,116 @@
+import logging
+
+from django.db.models import Exists
+from django.db.models import OuterRef
+from django.db.models import Prefetch
+
+from documents.models import Workflow
+from documents.models import WorkflowAction
+from documents.models import WorkflowTrigger
+
+logger = logging.getLogger("paperless.workflows")
+
+
+def get_workflows_for_trigger(
+ trigger_type: WorkflowTrigger.WorkflowTriggerType,
+ workflow_to_run: Workflow | None = None,
+):
+ """
+ Return workflows relevant to a trigger. If a specific workflow is given,
+ wrap it in a list; otherwise fetch enabled workflows for the trigger with
+ the prefetches used by the runner.
+ """
+ if workflow_to_run is not None:
+ return [workflow_to_run]
+
+ annotated_actions = (
+ WorkflowAction.objects.select_related(
+ "assign_correspondent",
+ "assign_document_type",
+ "assign_storage_path",
+ "assign_owner",
+ "email",
+ "webhook",
+ )
+ .prefetch_related(
+ "assign_tags",
+ "assign_view_users",
+ "assign_view_groups",
+ "assign_change_users",
+ "assign_change_groups",
+ "assign_custom_fields",
+ "remove_tags",
+ "remove_correspondents",
+ "remove_document_types",
+ "remove_storage_paths",
+ "remove_custom_fields",
+ "remove_owners",
+ )
+ .annotate(
+ has_assign_tags=Exists(
+ WorkflowAction.assign_tags.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_assign_view_users=Exists(
+ WorkflowAction.assign_view_users.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_assign_view_groups=Exists(
+ WorkflowAction.assign_view_groups.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_assign_change_users=Exists(
+ WorkflowAction.assign_change_users.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_assign_change_groups=Exists(
+ WorkflowAction.assign_change_groups.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_assign_custom_fields=Exists(
+ WorkflowAction.assign_custom_fields.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_remove_view_users=Exists(
+ WorkflowAction.remove_view_users.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_remove_view_groups=Exists(
+ WorkflowAction.remove_view_groups.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_remove_change_users=Exists(
+ WorkflowAction.remove_change_users.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_remove_change_groups=Exists(
+ WorkflowAction.remove_change_groups.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ has_remove_custom_fields=Exists(
+ WorkflowAction.remove_custom_fields.through.objects.filter(
+ workflowaction_id=OuterRef("pk"),
+ ),
+ ),
+ )
+ )
+
+ return (
+ Workflow.objects.filter(enabled=True, triggers__type=trigger_type)
+ .prefetch_related(
+ Prefetch("actions", queryset=annotated_actions),
+ "triggers",
+ )
+ .order_by("order")
+ .distinct()
+ )
diff --git a/src/documents/workflows/webhooks.py b/src/documents/workflows/webhooks.py
new file mode 100644
index 000000000..c7bb9f7c2
--- /dev/null
+++ b/src/documents/workflows/webhooks.py
@@ -0,0 +1,96 @@
+import ipaddress
+import logging
+import socket
+from urllib.parse import urlparse
+
+import httpx
+from celery import shared_task
+from django.conf import settings
+
+logger = logging.getLogger("paperless.workflows.webhooks")
+
+
+def _is_public_ip(ip: str) -> bool:
+ try:
+ obj = ipaddress.ip_address(ip)
+ return not (
+ obj.is_private
+ or obj.is_loopback
+ or obj.is_link_local
+ or obj.is_multicast
+ or obj.is_unspecified
+ )
+ except ValueError: # pragma: no cover
+ return False
+
+
+def _resolve_first_ip(host: str) -> str | None:
+ try:
+ info = socket.getaddrinfo(host, None)
+ return info[0][4][0] if info else None
+ except Exception: # pragma: no cover
+ return None
+
+
+@shared_task(
+ retry_backoff=True,
+ autoretry_for=(httpx.HTTPStatusError,),
+ max_retries=3,
+ throws=(httpx.HTTPError,),
+)
+def send_webhook(
+ url: str,
+ data: str | dict,
+ headers: dict,
+ files: dict,
+ *,
+ as_json: bool = False,
+):
+ p = urlparse(url)
+ if p.scheme.lower() not in settings.WEBHOOKS_ALLOWED_SCHEMES or not p.hostname:
+ logger.warning("Webhook blocked: invalid scheme/hostname")
+ raise ValueError("Invalid URL scheme or hostname.")
+
+ port = p.port or (443 if p.scheme == "https" else 80)
+ if (
+ len(settings.WEBHOOKS_ALLOWED_PORTS) > 0
+ and port not in settings.WEBHOOKS_ALLOWED_PORTS
+ ):
+ logger.warning("Webhook blocked: port not permitted")
+ raise ValueError("Destination port not permitted.")
+
+ ip = _resolve_first_ip(p.hostname)
+ if not ip or (
+ not _is_public_ip(ip) and not settings.WEBHOOKS_ALLOW_INTERNAL_REQUESTS
+ ):
+ logger.warning("Webhook blocked: destination not allowed")
+ raise ValueError("Destination host is not allowed.")
+
+ try:
+ post_args = {
+ "url": url,
+ "headers": {
+ k: v for k, v in (headers or {}).items() if k.lower() != "host"
+ },
+ "files": files or None,
+ "timeout": 5.0,
+ "follow_redirects": False,
+ }
+ if as_json:
+ post_args["json"] = data
+ elif isinstance(data, dict):
+ post_args["data"] = data
+ else:
+ post_args["content"] = data
+
+ httpx.post(
+ **post_args,
+ ).raise_for_status()
+ logger.info(
+ f"Webhook sent to {url}",
+ )
+ except Exception as e:
+ logger.error(
+ f"Failed attempt sending webhook to {url}: {e}",
+ )
+ raise e
diff --git a/src/locale/en_US/LC_MESSAGES/django.po b/src/locale/en_US/LC_MESSAGES/django.po
index bc2985431..8e745a2e9 100644
--- a/src/locale/en_US/LC_MESSAGES/django.po
+++ b/src/locale/en_US/LC_MESSAGES/django.po
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-11-14 16:09+0000\n"
+"POT-Creation-Date: 2025-12-10 16:39+0000\n"
"PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n"
"Language-Team: English\n"
@@ -1224,35 +1224,35 @@ msgstr ""
msgid "Invalid regular expression: %(error)s"
msgstr ""
-#: documents/serialisers.py:619
+#: documents/serialisers.py:622
msgid "Invalid color."
msgstr ""
-#: documents/serialisers.py:1805
+#: documents/serialisers.py:1808
#, python-format
msgid "File type %(type)s not supported"
msgstr ""
-#: documents/serialisers.py:1849
+#: documents/serialisers.py:1852
#, python-format
msgid "Custom field id must be an integer: %(id)s"
msgstr ""
-#: documents/serialisers.py:1856
+#: documents/serialisers.py:1859
#, python-format
msgid "Custom field with id %(id)s does not exist"
msgstr ""
-#: documents/serialisers.py:1873 documents/serialisers.py:1883
+#: documents/serialisers.py:1876 documents/serialisers.py:1886
msgid ""
"Custom fields must be a list of integers or an object mapping ids to values."
msgstr ""
-#: documents/serialisers.py:1878
+#: documents/serialisers.py:1881
msgid "Some custom fields don't exist or were specified twice."
msgstr ""
-#: documents/serialisers.py:1993
+#: documents/serialisers.py:1996
msgid "Invalid variable detected."
msgstr ""