mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Compare commits
	
		
			18 Commits
		
	
	
		
			dependabot
			...
			dependabot
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ff1848072d | ||
| 
						 | 
					74b10db028 | ||
| 
						 | 
					cffb9c34f0 | ||
| 
						 | 
					6f52614817 | ||
| 
						 | 
					a0d3527d20 | ||
| 
						 | 
					4e64ca7ca6 | ||
| 
						 | 
					e9511bd3da | ||
| 
						 | 
					8b9ca75a90 | ||
| 
						 | 
					9f0a4ac19d | ||
| 
						 | 
					8f969ecab5 | ||
| 
						 | 
					245e52a4eb | ||
| 
						 | 
					a8c75d95d8 | ||
| 
						 | 
					d6e2456baf | ||
| 
						 | 
					3b75d3271e | ||
| 
						 | 
					e88816d141 | ||
| 
						 | 
					e5bd4713ac | ||
| 
						 | 
					b9aced07fb | ||
| 
						 | 
					6b55740f56 | 
@@ -26,7 +26,7 @@ dependencies = [
 | 
			
		||||
  # WARNING: django does not use semver.
 | 
			
		||||
  #          Only patch versions are guaranteed to not introduce breaking changes.
 | 
			
		||||
  "django~=5.2.5",
 | 
			
		||||
  "django-allauth[mfa,socialaccount]~=65.12.1",
 | 
			
		||||
  "django-allauth[mfa,socialaccount]~=65.4.0",
 | 
			
		||||
  "django-auditlog~=3.2.1",
 | 
			
		||||
  "django-cachalot~=2.8.0",
 | 
			
		||||
  "django-celery-results~=2.6.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -672,11 +672,33 @@
 | 
			
		||||
          <context context-type="linenumber">4</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="8461842260159597706" datatype="html">
 | 
			
		||||
        <source>Show</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">8</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">37</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">52</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="5724363929304709833" datatype="html">
 | 
			
		||||
        <source>lines</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">17</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="8838884664569764142" datatype="html">
 | 
			
		||||
        <source>Auto refresh</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">8</context>
 | 
			
		||||
          <context context-type="linenumber">21</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
 | 
			
		||||
@@ -687,11 +709,11 @@
 | 
			
		||||
        <source>Loading...</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">24</context>
 | 
			
		||||
          <context context-type="linenumber">38</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/logs/logs.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">36</context>
 | 
			
		||||
          <context context-type="linenumber">53</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/admin/tasks/tasks.component.html</context>
 | 
			
		||||
@@ -7259,25 +7281,25 @@
 | 
			
		||||
        <source>Print failed.</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">1455</context>
 | 
			
		||||
          <context context-type="linenumber">1460</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="6457245677384603573" datatype="html">
 | 
			
		||||
        <source>Error loading document for printing.</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">1463</context>
 | 
			
		||||
          <context context-type="linenumber">1472</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="6085793215710522488" datatype="html">
 | 
			
		||||
        <source>An error occurred loading tiff: <x id="PH" equiv-text="err.toString()"/></source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">1528</context>
 | 
			
		||||
          <context context-type="linenumber">1537</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">1532</context>
 | 
			
		||||
          <context context-type="linenumber">1541</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="4958946940233632319" datatype="html">
 | 
			
		||||
@@ -7881,17 +7903,6 @@
 | 
			
		||||
          <context context-type="linenumber">45</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="8461842260159597706" datatype="html">
 | 
			
		||||
        <source>Show</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/document-list/document-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">37</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/manage/saved-views/saved-views.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">52</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="5146398958364876914" datatype="html">
 | 
			
		||||
        <source>Sort</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@
 | 
			
		||||
    "jest": "30.2.0",
 | 
			
		||||
    "jest-environment-jsdom": "^30.2.0",
 | 
			
		||||
    "jest-junit": "^16.0.0",
 | 
			
		||||
    "jest-preset-angular": "^15.0.2",
 | 
			
		||||
    "jest-preset-angular": "^15.0.3",
 | 
			
		||||
    "jest-websocket-mock": "^2.5.0",
 | 
			
		||||
    "prettier-plugin-organize-imports": "^4.3.0",
 | 
			
		||||
    "ts-node": "~10.9.1",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										281
									
								
								src-ui/pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										281
									
								
								src-ui/pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@@ -160,8 +160,8 @@ importers:
 | 
			
		||||
        specifier: ^16.0.0
 | 
			
		||||
        version: 16.0.0
 | 
			
		||||
      jest-preset-angular:
 | 
			
		||||
        specifier: ^15.0.2
 | 
			
		||||
        version: 15.0.2(ccefccc315e3e4bd30d78eb49c90d46a)
 | 
			
		||||
        specifier: ^15.0.3
 | 
			
		||||
        version: 15.0.3(ccefccc315e3e4bd30d78eb49c90d46a)
 | 
			
		||||
      jest-websocket-mock:
 | 
			
		||||
        specifier: ^2.5.0
 | 
			
		||||
        version: 2.5.0
 | 
			
		||||
@@ -1257,8 +1257,8 @@ packages:
 | 
			
		||||
  '@emnapi/wasi-threads@1.1.0':
 | 
			
		||||
    resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
 | 
			
		||||
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==}
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [ppc64]
 | 
			
		||||
    os: [aix]
 | 
			
		||||
@@ -1275,8 +1275,8 @@ packages:
 | 
			
		||||
    cpu: [ppc64]
 | 
			
		||||
    os: [aix]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==}
 | 
			
		||||
  '@esbuild/android-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [android]
 | 
			
		||||
@@ -1293,8 +1293,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [android]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==}
 | 
			
		||||
  '@esbuild/android-arm@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm]
 | 
			
		||||
    os: [android]
 | 
			
		||||
@@ -1311,8 +1311,8 @@ packages:
 | 
			
		||||
    cpu: [arm]
 | 
			
		||||
    os: [android]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==}
 | 
			
		||||
  '@esbuild/android-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [android]
 | 
			
		||||
@@ -1329,8 +1329,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [android]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==}
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [darwin]
 | 
			
		||||
@@ -1347,8 +1347,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [darwin]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==}
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [darwin]
 | 
			
		||||
@@ -1365,8 +1365,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [darwin]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==}
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [freebsd]
 | 
			
		||||
@@ -1383,8 +1383,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [freebsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==}
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [freebsd]
 | 
			
		||||
@@ -1401,8 +1401,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [freebsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==}
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1419,8 +1419,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==}
 | 
			
		||||
  '@esbuild/linux-arm@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1437,8 +1437,8 @@ packages:
 | 
			
		||||
    cpu: [arm]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==}
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [ia32]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1455,8 +1455,8 @@ packages:
 | 
			
		||||
    cpu: [ia32]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==}
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [loong64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1473,8 +1473,8 @@ packages:
 | 
			
		||||
    cpu: [loong64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==}
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [mips64el]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1491,8 +1491,8 @@ packages:
 | 
			
		||||
    cpu: [mips64el]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==}
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [ppc64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1509,8 +1509,8 @@ packages:
 | 
			
		||||
    cpu: [ppc64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==}
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [riscv64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1527,8 +1527,8 @@ packages:
 | 
			
		||||
    cpu: [riscv64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==}
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [s390x]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1545,8 +1545,8 @@ packages:
 | 
			
		||||
    cpu: [s390x]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==}
 | 
			
		||||
  '@esbuild/linux-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
@@ -1563,8 +1563,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [linux]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==}
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [netbsd]
 | 
			
		||||
@@ -1581,8 +1581,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [netbsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==}
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [netbsd]
 | 
			
		||||
@@ -1599,8 +1599,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [netbsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==}
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [openbsd]
 | 
			
		||||
@@ -1617,8 +1617,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [openbsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==}
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [openbsd]
 | 
			
		||||
@@ -1635,8 +1635,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [openbsd]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openharmony-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==}
 | 
			
		||||
  '@esbuild/openharmony-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [openharmony]
 | 
			
		||||
@@ -1647,8 +1647,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [openharmony]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==}
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [sunos]
 | 
			
		||||
@@ -1665,8 +1665,8 @@ packages:
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [sunos]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==}
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [win32]
 | 
			
		||||
@@ -1683,8 +1683,8 @@ packages:
 | 
			
		||||
    cpu: [arm64]
 | 
			
		||||
    os: [win32]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==}
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [ia32]
 | 
			
		||||
    os: [win32]
 | 
			
		||||
@@ -1701,8 +1701,8 @@ packages:
 | 
			
		||||
    cpu: [ia32]
 | 
			
		||||
    os: [win32]
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-x64@0.25.10':
 | 
			
		||||
    resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==}
 | 
			
		||||
  '@esbuild/win32-x64@0.25.11':
 | 
			
		||||
    resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    cpu: [x64]
 | 
			
		||||
    os: [win32]
 | 
			
		||||
@@ -3660,6 +3660,10 @@ packages:
 | 
			
		||||
    resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==}
 | 
			
		||||
    engines: {node: '>=8'}
 | 
			
		||||
 | 
			
		||||
  ci-info@4.3.1:
 | 
			
		||||
    resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==}
 | 
			
		||||
    engines: {node: '>=8'}
 | 
			
		||||
 | 
			
		||||
  cjs-module-lexer@2.1.0:
 | 
			
		||||
    resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==}
 | 
			
		||||
 | 
			
		||||
@@ -4064,8 +4068,8 @@ packages:
 | 
			
		||||
    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
 | 
			
		||||
    engines: {node: '>= 0.4'}
 | 
			
		||||
 | 
			
		||||
  esbuild-wasm@0.25.10:
 | 
			
		||||
    resolution: {integrity: sha512-IyyfrTA2iiOh/uhlaJj0aUDgW42lFhr29ZeKouVNOz/8mLyuqWbEuVst+B4RBH18pb3AcOHnaOgyskAbsVOe3A==}
 | 
			
		||||
  esbuild-wasm@0.25.11:
 | 
			
		||||
    resolution: {integrity: sha512-60gllbYFIRGzB6KALBB5Va9Wy3VeCi2U0NgmM7r+TFnRgzeEyoCn2D7fhacW2zWbd7MUeTKLDE7RlfYGBQ00bw==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
 | 
			
		||||
@@ -4074,8 +4078,8 @@ packages:
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
 | 
			
		||||
  esbuild@0.25.10:
 | 
			
		||||
    resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==}
 | 
			
		||||
  esbuild@0.25.11:
 | 
			
		||||
    resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
 | 
			
		||||
    engines: {node: '>=18'}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
 | 
			
		||||
@@ -4886,8 +4890,8 @@ packages:
 | 
			
		||||
      jsdom:
 | 
			
		||||
        optional: true
 | 
			
		||||
 | 
			
		||||
  jest-preset-angular@15.0.2:
 | 
			
		||||
    resolution: {integrity: sha512-XQNKL2BQllWF+eeiLuooMnL23IJ2s7yg7YfX52KhUMmwCTD0HlrU5RLzAgbP7xrsplsGWFlQwCe2kTJss/q0UQ==}
 | 
			
		||||
  jest-preset-angular@15.0.3:
 | 
			
		||||
    resolution: {integrity: sha512-W1OpeQ/tq72ZSGXRvUDktL02QBAWIM5SZPK4KI0zoXNvRGiGhNMbxuaFF7anLi27cojmWHm+TewJQI1Dsm9s6A==}
 | 
			
		||||
    engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
      '@angular/compiler-cli': '>=18.0.0 <21.0.0'
 | 
			
		||||
@@ -6072,6 +6076,11 @@ packages:
 | 
			
		||||
    engines: {node: '>=10'}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
 | 
			
		||||
  semver@7.7.3:
 | 
			
		||||
    resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
 | 
			
		||||
    engines: {node: '>=10'}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
 | 
			
		||||
  send@0.19.0:
 | 
			
		||||
    resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
 | 
			
		||||
    engines: {node: '>= 0.8.0'}
 | 
			
		||||
@@ -6443,8 +6452,8 @@ packages:
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
      typescript: '>=4.8.4'
 | 
			
		||||
 | 
			
		||||
  ts-jest@29.4.4:
 | 
			
		||||
    resolution: {integrity: sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==}
 | 
			
		||||
  ts-jest@29.4.5:
 | 
			
		||||
    resolution: {integrity: sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==}
 | 
			
		||||
    engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
 | 
			
		||||
    hasBin: true
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
@@ -8485,7 +8494,7 @@ snapshots:
 | 
			
		||||
      tslib: 2.8.1
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.10':
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.5':
 | 
			
		||||
@@ -8494,7 +8503,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/aix-ppc64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/android-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm64@0.25.5':
 | 
			
		||||
@@ -8503,7 +8512,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/android-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm@0.25.10':
 | 
			
		||||
  '@esbuild/android-arm@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-arm@0.25.5':
 | 
			
		||||
@@ -8512,7 +8521,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/android-arm@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-x64@0.25.10':
 | 
			
		||||
  '@esbuild/android-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/android-x64@0.25.5':
 | 
			
		||||
@@ -8521,7 +8530,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/android-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.5':
 | 
			
		||||
@@ -8530,7 +8539,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/darwin-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.10':
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.5':
 | 
			
		||||
@@ -8539,7 +8548,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/darwin-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.5':
 | 
			
		||||
@@ -8548,7 +8557,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/freebsd-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.10':
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.5':
 | 
			
		||||
@@ -8557,7 +8566,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/freebsd-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.5':
 | 
			
		||||
@@ -8566,7 +8575,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm@0.25.10':
 | 
			
		||||
  '@esbuild/linux-arm@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-arm@0.25.5':
 | 
			
		||||
@@ -8575,7 +8584,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-arm@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.10':
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.5':
 | 
			
		||||
@@ -8584,7 +8593,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-ia32@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.10':
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.5':
 | 
			
		||||
@@ -8593,7 +8602,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-loong64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.10':
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.5':
 | 
			
		||||
@@ -8602,7 +8611,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-mips64el@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.10':
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.5':
 | 
			
		||||
@@ -8611,7 +8620,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-ppc64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.10':
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.5':
 | 
			
		||||
@@ -8620,7 +8629,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-riscv64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.10':
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.5':
 | 
			
		||||
@@ -8629,7 +8638,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-s390x@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-x64@0.25.10':
 | 
			
		||||
  '@esbuild/linux-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/linux-x64@0.25.5':
 | 
			
		||||
@@ -8638,7 +8647,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/linux-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.5':
 | 
			
		||||
@@ -8647,7 +8656,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/netbsd-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.10':
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.5':
 | 
			
		||||
@@ -8656,7 +8665,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/netbsd-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.5':
 | 
			
		||||
@@ -8665,7 +8674,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/openbsd-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.10':
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.5':
 | 
			
		||||
@@ -8674,13 +8683,13 @@ snapshots:
 | 
			
		||||
  '@esbuild/openbsd-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openharmony-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/openharmony-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/openharmony-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.10':
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.5':
 | 
			
		||||
@@ -8689,7 +8698,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/sunos-x64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.10':
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.5':
 | 
			
		||||
@@ -8698,7 +8707,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/win32-arm64@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.10':
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.5':
 | 
			
		||||
@@ -8707,7 +8716,7 @@ snapshots:
 | 
			
		||||
  '@esbuild/win32-ia32@0.25.9':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-x64@0.25.10':
 | 
			
		||||
  '@esbuild/win32-x64@0.25.11':
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  '@esbuild/win32-x64@0.25.5':
 | 
			
		||||
@@ -10732,6 +10741,8 @@ snapshots:
 | 
			
		||||
 | 
			
		||||
  ci-info@4.3.0: {}
 | 
			
		||||
 | 
			
		||||
  ci-info@4.3.1: {}
 | 
			
		||||
 | 
			
		||||
  cjs-module-lexer@2.1.0: {}
 | 
			
		||||
 | 
			
		||||
  cli-cursor@5.0.0:
 | 
			
		||||
@@ -11083,38 +11094,38 @@ snapshots:
 | 
			
		||||
    dependencies:
 | 
			
		||||
      es-errors: 1.3.0
 | 
			
		||||
 | 
			
		||||
  esbuild-wasm@0.25.10: {}
 | 
			
		||||
  esbuild-wasm@0.25.11: {}
 | 
			
		||||
 | 
			
		||||
  esbuild-wasm@0.25.5: {}
 | 
			
		||||
 | 
			
		||||
  esbuild@0.25.10:
 | 
			
		||||
  esbuild@0.25.11:
 | 
			
		||||
    optionalDependencies:
 | 
			
		||||
      '@esbuild/aix-ppc64': 0.25.10
 | 
			
		||||
      '@esbuild/android-arm': 0.25.10
 | 
			
		||||
      '@esbuild/android-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/android-x64': 0.25.10
 | 
			
		||||
      '@esbuild/darwin-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/darwin-x64': 0.25.10
 | 
			
		||||
      '@esbuild/freebsd-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/freebsd-x64': 0.25.10
 | 
			
		||||
      '@esbuild/linux-arm': 0.25.10
 | 
			
		||||
      '@esbuild/linux-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/linux-ia32': 0.25.10
 | 
			
		||||
      '@esbuild/linux-loong64': 0.25.10
 | 
			
		||||
      '@esbuild/linux-mips64el': 0.25.10
 | 
			
		||||
      '@esbuild/linux-ppc64': 0.25.10
 | 
			
		||||
      '@esbuild/linux-riscv64': 0.25.10
 | 
			
		||||
      '@esbuild/linux-s390x': 0.25.10
 | 
			
		||||
      '@esbuild/linux-x64': 0.25.10
 | 
			
		||||
      '@esbuild/netbsd-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/netbsd-x64': 0.25.10
 | 
			
		||||
      '@esbuild/openbsd-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/openbsd-x64': 0.25.10
 | 
			
		||||
      '@esbuild/openharmony-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/sunos-x64': 0.25.10
 | 
			
		||||
      '@esbuild/win32-arm64': 0.25.10
 | 
			
		||||
      '@esbuild/win32-ia32': 0.25.10
 | 
			
		||||
      '@esbuild/win32-x64': 0.25.10
 | 
			
		||||
      '@esbuild/aix-ppc64': 0.25.11
 | 
			
		||||
      '@esbuild/android-arm': 0.25.11
 | 
			
		||||
      '@esbuild/android-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/android-x64': 0.25.11
 | 
			
		||||
      '@esbuild/darwin-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/darwin-x64': 0.25.11
 | 
			
		||||
      '@esbuild/freebsd-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/freebsd-x64': 0.25.11
 | 
			
		||||
      '@esbuild/linux-arm': 0.25.11
 | 
			
		||||
      '@esbuild/linux-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/linux-ia32': 0.25.11
 | 
			
		||||
      '@esbuild/linux-loong64': 0.25.11
 | 
			
		||||
      '@esbuild/linux-mips64el': 0.25.11
 | 
			
		||||
      '@esbuild/linux-ppc64': 0.25.11
 | 
			
		||||
      '@esbuild/linux-riscv64': 0.25.11
 | 
			
		||||
      '@esbuild/linux-s390x': 0.25.11
 | 
			
		||||
      '@esbuild/linux-x64': 0.25.11
 | 
			
		||||
      '@esbuild/netbsd-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/netbsd-x64': 0.25.11
 | 
			
		||||
      '@esbuild/openbsd-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/openbsd-x64': 0.25.11
 | 
			
		||||
      '@esbuild/openharmony-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/sunos-x64': 0.25.11
 | 
			
		||||
      '@esbuild/win32-arm64': 0.25.11
 | 
			
		||||
      '@esbuild/win32-ia32': 0.25.11
 | 
			
		||||
      '@esbuild/win32-x64': 0.25.11
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  esbuild@0.25.5:
 | 
			
		||||
@@ -12164,15 +12175,15 @@ snapshots:
 | 
			
		||||
      '@angular/core': 20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1)
 | 
			
		||||
      '@angular/platform-browser-dynamic': 20.3.2(@angular/common@20.3.2(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.2)(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.2(@angular/common@20.3.2(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1)))
 | 
			
		||||
      bs-logger: 0.2.6
 | 
			
		||||
      esbuild-wasm: 0.25.10
 | 
			
		||||
      esbuild-wasm: 0.25.11
 | 
			
		||||
      jest: 30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3))
 | 
			
		||||
      jest-environment-jsdom: 29.7.0(canvas@3.0.0)
 | 
			
		||||
      jest-util: 29.7.0
 | 
			
		||||
      pretty-format: 29.7.0
 | 
			
		||||
      ts-jest: 29.4.4(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3)
 | 
			
		||||
      ts-jest: 29.4.5(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.11)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3)
 | 
			
		||||
      typescript: 5.8.3
 | 
			
		||||
    optionalDependencies:
 | 
			
		||||
      esbuild: 0.25.10
 | 
			
		||||
      esbuild: 0.25.11
 | 
			
		||||
      jsdom: 26.1.0(canvas@3.0.0)
 | 
			
		||||
    transitivePeerDependencies:
 | 
			
		||||
      - '@babel/core'
 | 
			
		||||
@@ -12184,7 +12195,7 @@ snapshots:
 | 
			
		||||
      - supports-color
 | 
			
		||||
      - utf-8-validate
 | 
			
		||||
 | 
			
		||||
  jest-preset-angular@15.0.2(ccefccc315e3e4bd30d78eb49c90d46a):
 | 
			
		||||
  jest-preset-angular@15.0.3(ccefccc315e3e4bd30d78eb49c90d46a):
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@angular/compiler-cli': 20.3.2(@angular/compiler@20.3.2)(typescript@5.8.3)
 | 
			
		||||
      '@angular/core': 20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1)
 | 
			
		||||
@@ -12192,15 +12203,15 @@ snapshots:
 | 
			
		||||
      '@angular/platform-browser-dynamic': 20.3.2(@angular/common@20.3.2(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.2)(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.2(@angular/common@20.3.2(@angular/core@20.3.2(@angular/compiler@20.3.2)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.2(@angular/compiler@20.3.2)(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.25.10
 | 
			
		||||
      esbuild-wasm: 0.25.11
 | 
			
		||||
      jest: 30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3))
 | 
			
		||||
      jest-util: 30.2.0
 | 
			
		||||
      jsdom: 26.1.0(canvas@3.0.0)
 | 
			
		||||
      pretty-format: 30.2.0
 | 
			
		||||
      ts-jest: 29.4.4(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3)
 | 
			
		||||
      ts-jest: 29.4.5(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.11)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3)
 | 
			
		||||
      typescript: 5.8.3
 | 
			
		||||
    optionalDependencies:
 | 
			
		||||
      esbuild: 0.25.10
 | 
			
		||||
      esbuild: 0.25.11
 | 
			
		||||
    transitivePeerDependencies:
 | 
			
		||||
      - '@babel/core'
 | 
			
		||||
      - '@jest/transform'
 | 
			
		||||
@@ -12303,7 +12314,7 @@ snapshots:
 | 
			
		||||
      jest-message-util: 30.2.0
 | 
			
		||||
      jest-util: 30.2.0
 | 
			
		||||
      pretty-format: 30.2.0
 | 
			
		||||
      semver: 7.7.2
 | 
			
		||||
      semver: 7.7.3
 | 
			
		||||
      synckit: 0.11.11
 | 
			
		||||
    transitivePeerDependencies:
 | 
			
		||||
      - supports-color
 | 
			
		||||
@@ -12322,7 +12333,7 @@ snapshots:
 | 
			
		||||
      '@jest/types': 30.0.5
 | 
			
		||||
      '@types/node': 24.6.1
 | 
			
		||||
      chalk: 4.1.2
 | 
			
		||||
      ci-info: 4.3.0
 | 
			
		||||
      ci-info: 4.3.1
 | 
			
		||||
      graceful-fs: 4.2.11
 | 
			
		||||
      picomatch: 4.0.3
 | 
			
		||||
 | 
			
		||||
@@ -12331,7 +12342,7 @@ snapshots:
 | 
			
		||||
      '@jest/types': 30.2.0
 | 
			
		||||
      '@types/node': 24.6.1
 | 
			
		||||
      chalk: 4.1.2
 | 
			
		||||
      ci-info: 4.3.0
 | 
			
		||||
      ci-info: 4.3.1
 | 
			
		||||
      graceful-fs: 4.2.11
 | 
			
		||||
      picomatch: 4.0.3
 | 
			
		||||
 | 
			
		||||
@@ -12649,7 +12660,7 @@ snapshots:
 | 
			
		||||
 | 
			
		||||
  make-dir@4.0.0:
 | 
			
		||||
    dependencies:
 | 
			
		||||
      semver: 7.7.2
 | 
			
		||||
      semver: 7.7.3
 | 
			
		||||
 | 
			
		||||
  make-error@1.3.6: {}
 | 
			
		||||
 | 
			
		||||
@@ -12904,7 +12915,7 @@ snapshots:
 | 
			
		||||
 | 
			
		||||
  node-abi@3.71.0:
 | 
			
		||||
    dependencies:
 | 
			
		||||
      semver: 7.7.2
 | 
			
		||||
      semver: 7.7.3
 | 
			
		||||
    optional: true
 | 
			
		||||
 | 
			
		||||
  node-addon-api@6.1.0:
 | 
			
		||||
@@ -13625,6 +13636,8 @@ snapshots:
 | 
			
		||||
 | 
			
		||||
  semver@7.7.2: {}
 | 
			
		||||
 | 
			
		||||
  semver@7.7.3: {}
 | 
			
		||||
 | 
			
		||||
  send@0.19.0:
 | 
			
		||||
    dependencies:
 | 
			
		||||
      debug: 2.6.9
 | 
			
		||||
@@ -14085,7 +14098,7 @@ snapshots:
 | 
			
		||||
    dependencies:
 | 
			
		||||
      typescript: 5.8.3
 | 
			
		||||
 | 
			
		||||
  ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3):
 | 
			
		||||
  ts-jest@29.4.5(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.11)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3):
 | 
			
		||||
    dependencies:
 | 
			
		||||
      bs-logger: 0.2.6
 | 
			
		||||
      fast-json-stable-stringify: 2.1.0
 | 
			
		||||
@@ -14094,7 +14107,7 @@ snapshots:
 | 
			
		||||
      json5: 2.2.3
 | 
			
		||||
      lodash.memoize: 4.1.2
 | 
			
		||||
      make-error: 1.3.6
 | 
			
		||||
      semver: 7.7.2
 | 
			
		||||
      semver: 7.7.3
 | 
			
		||||
      type-fest: 4.41.0
 | 
			
		||||
      typescript: 5.8.3
 | 
			
		||||
      yargs-parser: 21.1.1
 | 
			
		||||
@@ -14103,10 +14116,10 @@ snapshots:
 | 
			
		||||
      '@jest/transform': 30.2.0
 | 
			
		||||
      '@jest/types': 30.2.0
 | 
			
		||||
      babel-jest: 30.2.0(@babel/core@7.28.4)
 | 
			
		||||
      esbuild: 0.25.10
 | 
			
		||||
      esbuild: 0.25.11
 | 
			
		||||
      jest-util: 29.7.0
 | 
			
		||||
 | 
			
		||||
  ts-jest@29.4.4(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3):
 | 
			
		||||
  ts-jest@29.4.5(@babel/core@7.28.4)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.4))(esbuild@0.25.11)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.6.1)(ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3)))(typescript@5.8.3):
 | 
			
		||||
    dependencies:
 | 
			
		||||
      bs-logger: 0.2.6
 | 
			
		||||
      fast-json-stable-stringify: 2.1.0
 | 
			
		||||
@@ -14115,7 +14128,7 @@ snapshots:
 | 
			
		||||
      json5: 2.2.3
 | 
			
		||||
      lodash.memoize: 4.1.2
 | 
			
		||||
      make-error: 1.3.6
 | 
			
		||||
      semver: 7.7.2
 | 
			
		||||
      semver: 7.7.3
 | 
			
		||||
      type-fest: 4.41.0
 | 
			
		||||
      typescript: 5.8.3
 | 
			
		||||
      yargs-parser: 21.1.1
 | 
			
		||||
@@ -14124,7 +14137,7 @@ snapshots:
 | 
			
		||||
      '@jest/transform': 30.2.0
 | 
			
		||||
      '@jest/types': 30.2.0
 | 
			
		||||
      babel-jest: 30.2.0(@babel/core@7.28.4)
 | 
			
		||||
      esbuild: 0.25.10
 | 
			
		||||
      esbuild: 0.25.11
 | 
			
		||||
      jest-util: 30.2.0
 | 
			
		||||
 | 
			
		||||
  ts-node@10.9.2(@types/node@24.6.1)(typescript@5.8.3):
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,23 @@
 | 
			
		||||
  i18n-title
 | 
			
		||||
  info="Review the log files for the application and for email checking."
 | 
			
		||||
  i18n-info>
 | 
			
		||||
  <div class="form-check form-switch">
 | 
			
		||||
    <input class="form-check-input" type="checkbox" role="switch" [(ngModel)]="autoRefreshEnabled">
 | 
			
		||||
    <label class="form-check-label" for="autoRefreshSwitch" i18n>Auto refresh</label>
 | 
			
		||||
  <div class="input-group input-group-sm align-items-center">
 | 
			
		||||
    <div class="input-group input-group-sm me-3">
 | 
			
		||||
      <span class="input-group-text text-muted" i18n>Show</span>
 | 
			
		||||
      <input
 | 
			
		||||
        class="form-control"
 | 
			
		||||
        type="number"
 | 
			
		||||
        min="100"
 | 
			
		||||
        step="100"
 | 
			
		||||
        [(ngModel)]="limit"
 | 
			
		||||
        (ngModelChange)="onLimitChange($event)"
 | 
			
		||||
        style="width: 100px;">
 | 
			
		||||
      <span class="input-group-text text-muted" i18n>lines</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-check form-switch mt-1">
 | 
			
		||||
      <input class="form-check-input" type="checkbox" role="switch" [(ngModel)]="autoRefreshEnabled">
 | 
			
		||||
      <label class="form-check-label" for="autoRefreshSwitch" i18n>Auto refresh</label>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</pngx-page-header>
 | 
			
		||||
 | 
			
		||||
@@ -29,14 +43,19 @@
 | 
			
		||||
 | 
			
		||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
 | 
			
		||||
 | 
			
		||||
<div class="bg-dark p-3 text-light font-monospace log-container" #logContainer>
 | 
			
		||||
<cdk-virtual-scroll-viewport
 | 
			
		||||
  itemSize="20"
 | 
			
		||||
  class="bg-dark p-3 text-light font-monospace log-container"
 | 
			
		||||
  #logContainer>
 | 
			
		||||
  @if (loading && logFiles.length) {
 | 
			
		||||
    <div>
 | 
			
		||||
      <div class="spinner-border spinner-border-sm me-2" role="status"></div>
 | 
			
		||||
      <ng-container i18n>Loading...</ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
  }
 | 
			
		||||
  @for (log of logs; track $index) {
 | 
			
		||||
    <p class="m-0 p-0 log-entry-{{getLogLevel(log)}}">{{log}}</p>
 | 
			
		||||
  }
 | 
			
		||||
</div>
 | 
			
		||||
  <p *cdkVirtualFor="let log of logs"
 | 
			
		||||
     class="m-0 p-0"
 | 
			
		||||
     [ngClass]="'log-entry-' + log.level">
 | 
			
		||||
    {{log.message}}
 | 
			
		||||
  </p>
 | 
			
		||||
</cdk-virtual-scroll-viewport>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
.log-container {
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  height: calc(100vh - 200px);
 | 
			
		||||
  top: 70px;
 | 
			
		||||
  top: 0;
 | 
			
		||||
 | 
			
		||||
  p {
 | 
			
		||||
    white-space: pre-wrap;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,8 @@
 | 
			
		||||
import {
 | 
			
		||||
  CdkVirtualScrollViewport,
 | 
			
		||||
  ScrollingModule,
 | 
			
		||||
} from '@angular/cdk/scrolling'
 | 
			
		||||
import { CommonModule } from '@angular/common'
 | 
			
		||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
 | 
			
		||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
 | 
			
		||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
 | 
			
		||||
@@ -38,6 +43,9 @@ describe('LogsComponent', () => {
 | 
			
		||||
        NgxBootstrapIconsModule.pick(allIcons),
 | 
			
		||||
        LogsComponent,
 | 
			
		||||
        PageHeaderComponent,
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        CdkVirtualScrollViewport,
 | 
			
		||||
        ScrollingModule,
 | 
			
		||||
      ],
 | 
			
		||||
      providers: [
 | 
			
		||||
        provideHttpClient(withInterceptorsFromDi()),
 | 
			
		||||
@@ -54,13 +62,12 @@ describe('LogsComponent', () => {
 | 
			
		||||
    fixture = TestBed.createComponent(LogsComponent)
 | 
			
		||||
    component = fixture.componentInstance
 | 
			
		||||
    reloadSpy = jest.spyOn(component, 'reloadLogs')
 | 
			
		||||
    window.HTMLElement.prototype.scroll = function () {} // mock scroll
 | 
			
		||||
    jest.useFakeTimers()
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should display logs with first log initially', () => {
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith('paperless')
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith('paperless', 5000)
 | 
			
		||||
    fixture.detectChanges()
 | 
			
		||||
    expect(fixture.debugElement.nativeElement.textContent).toContain(
 | 
			
		||||
      paperless_logs[0]
 | 
			
		||||
@@ -71,7 +78,7 @@ describe('LogsComponent', () => {
 | 
			
		||||
    fixture.debugElement
 | 
			
		||||
      .queryAll(By.directive(NgbNavLink))[1]
 | 
			
		||||
      .nativeElement.dispatchEvent(new MouseEvent('click'))
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith('mail')
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith('mail', 5000)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should handle error with no logs', () => {
 | 
			
		||||
@@ -83,6 +90,10 @@ describe('LogsComponent', () => {
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should auto refresh, allow toggle', () => {
 | 
			
		||||
    jest
 | 
			
		||||
      .spyOn(CdkVirtualScrollViewport.prototype, 'scrollToIndex')
 | 
			
		||||
      .mockImplementation(() => undefined)
 | 
			
		||||
 | 
			
		||||
    jest.advanceTimersByTime(6000)
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalledTimes(2)
 | 
			
		||||
 | 
			
		||||
@@ -90,4 +101,13 @@ describe('LogsComponent', () => {
 | 
			
		||||
    jest.advanceTimersByTime(6000)
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalledTimes(2)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should debounce limit changes before reloading logs', () => {
 | 
			
		||||
    const initialCalls = reloadSpy.mock.calls.length
 | 
			
		||||
    component.onLimitChange(6000)
 | 
			
		||||
    jest.advanceTimersByTime(299)
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalledTimes(initialCalls)
 | 
			
		||||
    jest.advanceTimersByTime(1)
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalledTimes(initialCalls + 1)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,11 @@
 | 
			
		||||
import {
 | 
			
		||||
  CdkVirtualScrollViewport,
 | 
			
		||||
  ScrollingModule,
 | 
			
		||||
} from '@angular/cdk/scrolling'
 | 
			
		||||
import { CommonModule } from '@angular/common'
 | 
			
		||||
import {
 | 
			
		||||
  ChangeDetectorRef,
 | 
			
		||||
  Component,
 | 
			
		||||
  ElementRef,
 | 
			
		||||
  OnDestroy,
 | 
			
		||||
  OnInit,
 | 
			
		||||
  ViewChild,
 | 
			
		||||
@@ -9,7 +13,7 @@ import {
 | 
			
		||||
} from '@angular/core'
 | 
			
		||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
 | 
			
		||||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'
 | 
			
		||||
import { filter, takeUntil, timer } from 'rxjs'
 | 
			
		||||
import { Subject, debounceTime, filter, takeUntil, timer } from 'rxjs'
 | 
			
		||||
import { LogService } from 'src/app/services/rest/log.service'
 | 
			
		||||
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
 | 
			
		||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
 | 
			
		||||
@@ -21,8 +25,11 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
 | 
			
		||||
  imports: [
 | 
			
		||||
    PageHeaderComponent,
 | 
			
		||||
    NgbNavModule,
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    FormsModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
    CdkVirtualScrollViewport,
 | 
			
		||||
    ScrollingModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class LogsComponent
 | 
			
		||||
@@ -32,7 +39,7 @@ export class LogsComponent
 | 
			
		||||
  private logService = inject(LogService)
 | 
			
		||||
  private changedetectorRef = inject(ChangeDetectorRef)
 | 
			
		||||
 | 
			
		||||
  public logs: string[] = []
 | 
			
		||||
  public logs: Array<{ message: string; level: number }> = []
 | 
			
		||||
 | 
			
		||||
  public logFiles: string[] = []
 | 
			
		||||
 | 
			
		||||
@@ -40,9 +47,17 @@ export class LogsComponent
 | 
			
		||||
 | 
			
		||||
  public autoRefreshEnabled: boolean = true
 | 
			
		||||
 | 
			
		||||
  @ViewChild('logContainer') logContainer: ElementRef
 | 
			
		||||
  public limit: number = 5000
 | 
			
		||||
 | 
			
		||||
  private readonly limitChange$ = new Subject<number>()
 | 
			
		||||
 | 
			
		||||
  @ViewChild('logContainer') logContainer: CdkVirtualScrollViewport
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.limitChange$
 | 
			
		||||
      .pipe(debounceTime(300), takeUntil(this.unsubscribeNotifier))
 | 
			
		||||
      .subscribe(() => this.reloadLogs())
 | 
			
		||||
 | 
			
		||||
    this.logService
 | 
			
		||||
      .list()
 | 
			
		||||
      .pipe(takeUntil(this.unsubscribeNotifier))
 | 
			
		||||
@@ -68,16 +83,33 @@ export class LogsComponent
 | 
			
		||||
    super.ngOnDestroy()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onLimitChange(limit: number): void {
 | 
			
		||||
    this.limitChange$.next(limit)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  reloadLogs() {
 | 
			
		||||
    this.loading = true
 | 
			
		||||
    this.logService
 | 
			
		||||
      .get(this.activeLog)
 | 
			
		||||
      .get(this.activeLog, this.limit)
 | 
			
		||||
      .pipe(takeUntil(this.unsubscribeNotifier))
 | 
			
		||||
      .subscribe({
 | 
			
		||||
        next: (result) => {
 | 
			
		||||
          this.logs = result
 | 
			
		||||
          this.loading = false
 | 
			
		||||
          this.scrollToBottom()
 | 
			
		||||
          const parsed = this.parseLogsWithLevel(result)
 | 
			
		||||
          const hasChanges =
 | 
			
		||||
            parsed.length !== this.logs.length ||
 | 
			
		||||
            parsed.some((log, idx) => {
 | 
			
		||||
              const current = this.logs[idx]
 | 
			
		||||
              return (
 | 
			
		||||
                !current ||
 | 
			
		||||
                current.message !== log.message ||
 | 
			
		||||
                current.level !== log.level
 | 
			
		||||
              )
 | 
			
		||||
            })
 | 
			
		||||
          if (hasChanges) {
 | 
			
		||||
            this.logs = parsed
 | 
			
		||||
            this.scrollToBottom()
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        error: () => {
 | 
			
		||||
          this.logs = []
 | 
			
		||||
@@ -100,12 +132,19 @@ export class LogsComponent
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private parseLogsWithLevel(
 | 
			
		||||
    logs: string[]
 | 
			
		||||
  ): Array<{ message: string; level: number }> {
 | 
			
		||||
    return logs.map((log) => ({
 | 
			
		||||
      message: log,
 | 
			
		||||
      level: this.getLogLevel(log),
 | 
			
		||||
    }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  scrollToBottom(): void {
 | 
			
		||||
    this.changedetectorRef.detectChanges()
 | 
			
		||||
    this.logContainer?.nativeElement.scroll({
 | 
			
		||||
      top: this.logContainer.nativeElement.scrollHeight,
 | 
			
		||||
      left: 0,
 | 
			
		||||
      behavior: 'auto',
 | 
			
		||||
    })
 | 
			
		||||
    if (this.logContainer) {
 | 
			
		||||
      this.logContainer.scrollToIndex(this.logs.length - 1)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1489,6 +1489,8 @@ describe('DocumentDetailComponent', () => {
 | 
			
		||||
      mockContentWindow.onafterprint(new Event('afterprint'))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tick(500)
 | 
			
		||||
 | 
			
		||||
    expect(removeChildSpy).toHaveBeenCalledWith(mockIframe)
 | 
			
		||||
    expect(revokeObjectURLSpy).toHaveBeenCalledWith('blob:mock-url')
 | 
			
		||||
 | 
			
		||||
@@ -1512,65 +1514,97 @@ describe('DocumentDetailComponent', () => {
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should show error toast if printing throws inside iframe', fakeAsync(() => {
 | 
			
		||||
    initNormally()
 | 
			
		||||
  const iframePrintErrorCases: Array<{
 | 
			
		||||
    description: string
 | 
			
		||||
    thrownError: Error
 | 
			
		||||
    expectToast: boolean
 | 
			
		||||
  }> = [
 | 
			
		||||
    {
 | 
			
		||||
      description: 'should show error toast if printing throws inside iframe',
 | 
			
		||||
      thrownError: new Error('focus failed'),
 | 
			
		||||
      expectToast: true,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      description:
 | 
			
		||||
        'should suppress toast if cross-origin afterprint error occurs',
 | 
			
		||||
      thrownError: new DOMException(
 | 
			
		||||
        'Accessing onafterprint triggered a cross-origin violation',
 | 
			
		||||
        'SecurityError'
 | 
			
		||||
      ),
 | 
			
		||||
      expectToast: false,
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
    const appendChildSpy = jest
 | 
			
		||||
      .spyOn(document.body, 'appendChild')
 | 
			
		||||
      .mockImplementation((node: Node) => node)
 | 
			
		||||
    const removeChildSpy = jest
 | 
			
		||||
      .spyOn(document.body, 'removeChild')
 | 
			
		||||
      .mockImplementation((node: Node) => node)
 | 
			
		||||
    const createObjectURLSpy = jest
 | 
			
		||||
      .spyOn(URL, 'createObjectURL')
 | 
			
		||||
      .mockReturnValue('blob:mock-url')
 | 
			
		||||
    const revokeObjectURLSpy = jest
 | 
			
		||||
      .spyOn(URL, 'revokeObjectURL')
 | 
			
		||||
      .mockImplementation(() => {})
 | 
			
		||||
  iframePrintErrorCases.forEach(({ description, thrownError, expectToast }) => {
 | 
			
		||||
    it(
 | 
			
		||||
      description,
 | 
			
		||||
      fakeAsync(() => {
 | 
			
		||||
        initNormally()
 | 
			
		||||
 | 
			
		||||
    const toastSpy = jest.spyOn(toastService, 'showError')
 | 
			
		||||
        const appendChildSpy = jest
 | 
			
		||||
          .spyOn(document.body, 'appendChild')
 | 
			
		||||
          .mockImplementation((node: Node) => node)
 | 
			
		||||
        const removeChildSpy = jest
 | 
			
		||||
          .spyOn(document.body, 'removeChild')
 | 
			
		||||
          .mockImplementation((node: Node) => node)
 | 
			
		||||
        const createObjectURLSpy = jest
 | 
			
		||||
          .spyOn(URL, 'createObjectURL')
 | 
			
		||||
          .mockReturnValue('blob:mock-url')
 | 
			
		||||
        const revokeObjectURLSpy = jest
 | 
			
		||||
          .spyOn(URL, 'revokeObjectURL')
 | 
			
		||||
          .mockImplementation(() => {})
 | 
			
		||||
 | 
			
		||||
    const mockContentWindow = {
 | 
			
		||||
      focus: jest.fn().mockImplementation(() => {
 | 
			
		||||
        throw new Error('focus failed')
 | 
			
		||||
      }),
 | 
			
		||||
      print: jest.fn(),
 | 
			
		||||
      onafterprint: null,
 | 
			
		||||
    }
 | 
			
		||||
        const toastSpy = jest.spyOn(toastService, 'showError')
 | 
			
		||||
 | 
			
		||||
    const mockIframe: any = {
 | 
			
		||||
      style: {},
 | 
			
		||||
      src: '',
 | 
			
		||||
      onload: null,
 | 
			
		||||
      contentWindow: mockContentWindow,
 | 
			
		||||
    }
 | 
			
		||||
        const mockContentWindow = {
 | 
			
		||||
          focus: jest.fn().mockImplementation(() => {
 | 
			
		||||
            throw thrownError
 | 
			
		||||
          }),
 | 
			
		||||
          print: jest.fn(),
 | 
			
		||||
          onafterprint: null,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    const createElementSpy = jest
 | 
			
		||||
      .spyOn(document, 'createElement')
 | 
			
		||||
      .mockReturnValue(mockIframe as any)
 | 
			
		||||
        const mockIframe: any = {
 | 
			
		||||
          style: {},
 | 
			
		||||
          src: '',
 | 
			
		||||
          onload: null,
 | 
			
		||||
          contentWindow: mockContentWindow,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    const blob = new Blob(['test'], { type: 'application/pdf' })
 | 
			
		||||
    component.printDocument()
 | 
			
		||||
        const createElementSpy = jest
 | 
			
		||||
          .spyOn(document, 'createElement')
 | 
			
		||||
          .mockReturnValue(mockIframe as any)
 | 
			
		||||
 | 
			
		||||
    const req = httpTestingController.expectOne(
 | 
			
		||||
      `${environment.apiBaseUrl}documents/${doc.id}/download/`
 | 
			
		||||
        const blob = new Blob(['test'], { type: 'application/pdf' })
 | 
			
		||||
        component.printDocument()
 | 
			
		||||
 | 
			
		||||
        const req = httpTestingController.expectOne(
 | 
			
		||||
          `${environment.apiBaseUrl}documents/${doc.id}/download/`
 | 
			
		||||
        )
 | 
			
		||||
        req.flush(blob)
 | 
			
		||||
 | 
			
		||||
        tick()
 | 
			
		||||
 | 
			
		||||
        if (mockIframe.onload) {
 | 
			
		||||
          mockIframe.onload(new Event('load'))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tick(200)
 | 
			
		||||
 | 
			
		||||
        if (expectToast) {
 | 
			
		||||
          expect(toastSpy).toHaveBeenCalled()
 | 
			
		||||
        } else {
 | 
			
		||||
          expect(toastSpy).not.toHaveBeenCalled()
 | 
			
		||||
        }
 | 
			
		||||
        expect(removeChildSpy).toHaveBeenCalledWith(mockIframe)
 | 
			
		||||
        expect(revokeObjectURLSpy).toHaveBeenCalledWith('blob:mock-url')
 | 
			
		||||
 | 
			
		||||
        createElementSpy.mockRestore()
 | 
			
		||||
        appendChildSpy.mockRestore()
 | 
			
		||||
        removeChildSpy.mockRestore()
 | 
			
		||||
        createObjectURLSpy.mockRestore()
 | 
			
		||||
        revokeObjectURLSpy.mockRestore()
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
    req.flush(blob)
 | 
			
		||||
 | 
			
		||||
    tick()
 | 
			
		||||
 | 
			
		||||
    if (mockIframe.onload) {
 | 
			
		||||
      mockIframe.onload(new Event('load'))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    expect(toastSpy).toHaveBeenCalled()
 | 
			
		||||
    expect(removeChildSpy).toHaveBeenCalledWith(mockIframe)
 | 
			
		||||
    expect(revokeObjectURLSpy).toHaveBeenCalledWith('blob:mock-url')
 | 
			
		||||
 | 
			
		||||
    createElementSpy.mockRestore()
 | 
			
		||||
    appendChildSpy.mockRestore()
 | 
			
		||||
    removeChildSpy.mockRestore()
 | 
			
		||||
    createObjectURLSpy.mockRestore()
 | 
			
		||||
    revokeObjectURLSpy.mockRestore()
 | 
			
		||||
  }))
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'
 | 
			
		||||
import { PDFDocumentProxy, PdfViewerModule } from 'ng2-pdf-viewer'
 | 
			
		||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
 | 
			
		||||
import { DeviceDetectorService } from 'ngx-device-detector'
 | 
			
		||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs'
 | 
			
		||||
import { BehaviorSubject, Observable, of, Subject, timer } from 'rxjs'
 | 
			
		||||
import {
 | 
			
		||||
  catchError,
 | 
			
		||||
  debounceTime,
 | 
			
		||||
@@ -1452,9 +1452,18 @@ export class DocumentDetailComponent
 | 
			
		||||
                URL.revokeObjectURL(blobUrl)
 | 
			
		||||
              }
 | 
			
		||||
            } catch (err) {
 | 
			
		||||
              this.toastService.showError($localize`Print failed.`, err)
 | 
			
		||||
              document.body.removeChild(iframe)
 | 
			
		||||
              URL.revokeObjectURL(blobUrl)
 | 
			
		||||
              // FF throws cross-origin error on onafterprint
 | 
			
		||||
              const isCrossOriginAfterPrintError =
 | 
			
		||||
                err instanceof DOMException &&
 | 
			
		||||
                err.message.includes('onafterprint')
 | 
			
		||||
              if (!isCrossOriginAfterPrintError) {
 | 
			
		||||
                this.toastService.showError($localize`Print failed.`, err)
 | 
			
		||||
              }
 | 
			
		||||
              timer(100).subscribe(() => {
 | 
			
		||||
                // delay to avoid FF print failure
 | 
			
		||||
                document.body.removeChild(iframe)
 | 
			
		||||
                URL.revokeObjectURL(blobUrl)
 | 
			
		||||
              })
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@
 | 
			
		||||
              </td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <ng-template #errorPopover>
 | 
			
		||||
                  <pre class="small text-light">
 | 
			
		||||
                  <pre class="small">
 | 
			
		||||
                    {{ mail.error }}
 | 
			
		||||
                  </pre>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
::ng-deep .popover {
 | 
			
		||||
    max-width: 350px;
 | 
			
		||||
    max-height: 600px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
 | 
			
		||||
    pre {
 | 
			
		||||
        white-space: pre-wrap;
 | 
			
		||||
 
 | 
			
		||||
@@ -73,9 +73,14 @@ describe('TagListComponent', () => {
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should filter out child tags if name filter is empty, otherwise show all', () => {
 | 
			
		||||
  it('should omit matching children from top level when their parent is present', () => {
 | 
			
		||||
    const tags = [
 | 
			
		||||
      { id: 1, name: 'Tag1', parent: null },
 | 
			
		||||
      {
 | 
			
		||||
        id: 1,
 | 
			
		||||
        name: 'Tag1',
 | 
			
		||||
        parent: null,
 | 
			
		||||
        children: [{ id: 2, name: 'Tag2', parent: 1 }],
 | 
			
		||||
      },
 | 
			
		||||
      { id: 2, name: 'Tag2', parent: 1 },
 | 
			
		||||
      { id: 3, name: 'Tag3', parent: null },
 | 
			
		||||
    ]
 | 
			
		||||
@@ -86,7 +91,13 @@ describe('TagListComponent', () => {
 | 
			
		||||
 | 
			
		||||
    component['_nameFilter'] = 'Tag2' // Simulate non-empty name filter
 | 
			
		||||
    const filteredWithName = component.filterData(tags as any)
 | 
			
		||||
    expect(filteredWithName.length).toBe(3)
 | 
			
		||||
    expect(filteredWithName.length).toBe(2)
 | 
			
		||||
    expect(filteredWithName.find((t) => t.id === 2)).toBeUndefined()
 | 
			
		||||
    expect(
 | 
			
		||||
      filteredWithName
 | 
			
		||||
        .find((t) => t.id === 1)
 | 
			
		||||
        ?.children?.some((c) => c.id === 2)
 | 
			
		||||
    ).toBe(true)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should request only parent tags when no name filter is applied', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -69,9 +69,13 @@ export class TagListComponent extends ManagementListComponent<Tag> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterData(data: Tag[]) {
 | 
			
		||||
    return this.nameFilter?.length
 | 
			
		||||
      ? [...data]
 | 
			
		||||
      : data.filter((tag) => !tag.parent)
 | 
			
		||||
    if (!this.nameFilter?.length) {
 | 
			
		||||
      return data.filter((tag) => !tag.parent)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // When filtering by name, exclude children if their parent is also present
 | 
			
		||||
    const availableIds = new Set(data.map((tag) => tag.id))
 | 
			
		||||
    return data.filter((tag) => !tag.parent || !availableIds.has(tag.parent))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected override getSelectableIDs(tags: Tag[]): number[] {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,4 +49,14 @@ describe('LogService', () => {
 | 
			
		||||
    )
 | 
			
		||||
    expect(req.request.method).toEqual('GET')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should pass limit param on logs get when provided', () => {
 | 
			
		||||
    const id: string = 'mail'
 | 
			
		||||
    const limit: number = 100
 | 
			
		||||
    subscription = service.get(id, limit).subscribe()
 | 
			
		||||
    const req = httpTestingController.expectOne(
 | 
			
		||||
      `${environment.apiBaseUrl}${endpoint}/${id}/?limit=${limit}`
 | 
			
		||||
    )
 | 
			
		||||
    expect(req.request.method).toEqual('GET')
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { HttpClient } from '@angular/common/http'
 | 
			
		||||
import { HttpClient, HttpParams } from '@angular/common/http'
 | 
			
		||||
import { Injectable, inject } from '@angular/core'
 | 
			
		||||
import { Observable } from 'rxjs'
 | 
			
		||||
import { environment } from 'src/environments/environment'
 | 
			
		||||
@@ -13,7 +13,13 @@ export class LogService {
 | 
			
		||||
    return this.http.get<string[]>(`${environment.apiBaseUrl}logs/`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get(id: string): Observable<string[]> {
 | 
			
		||||
    return this.http.get<string[]>(`${environment.apiBaseUrl}logs/${id}/`)
 | 
			
		||||
  get(id: string, limit?: number): Observable<string[]> {
 | 
			
		||||
    let params = new HttpParams()
 | 
			
		||||
    if (limit !== undefined) {
 | 
			
		||||
      params = params.set('limit', limit.toString())
 | 
			
		||||
    }
 | 
			
		||||
    return this.http.get<string[]>(`${environment.apiBaseUrl}logs/${id}/`, {
 | 
			
		||||
      params,
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2250,6 +2250,23 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
 | 
			
		||||
        self.assertEqual(response.status_code, status.HTTP_200_OK)
 | 
			
		||||
        self.assertListEqual(response.data, ["test", "test2"])
 | 
			
		||||
 | 
			
		||||
    def test_get_log_with_limit(self):
 | 
			
		||||
        log_data = "test1\ntest2\ntest3\n"
 | 
			
		||||
        with (Path(settings.LOGGING_DIR) / "paperless.log").open("w") as f:
 | 
			
		||||
            f.write(log_data)
 | 
			
		||||
        response = self.client.get("/api/logs/paperless/", {"limit": 2})
 | 
			
		||||
        self.assertEqual(response.status_code, status.HTTP_200_OK)
 | 
			
		||||
        self.assertListEqual(response.data, ["test2", "test3"])
 | 
			
		||||
 | 
			
		||||
    def test_get_log_with_invalid_limit(self):
 | 
			
		||||
        log_data = "test1\ntest2\n"
 | 
			
		||||
        with (Path(settings.LOGGING_DIR) / "paperless.log").open("w") as f:
 | 
			
		||||
            f.write(log_data)
 | 
			
		||||
        response = self.client.get("/api/logs/paperless/", {"limit": "abc"})
 | 
			
		||||
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
        response = self.client.get("/api/logs/paperless/", {"limit": -5})
 | 
			
		||||
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
 | 
			
		||||
 | 
			
		||||
    def test_invalid_regex_other_algorithm(self):
 | 
			
		||||
        for endpoint in ["correspondents", "tags", "document_types"]:
 | 
			
		||||
            response = self.client.post(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
from django.core.cache import cache
 | 
			
		||||
from pytest_httpx import HTTPXMock
 | 
			
		||||
from rest_framework import status
 | 
			
		||||
from rest_framework.test import APIClient
 | 
			
		||||
@@ -8,6 +9,9 @@ from paperless import version
 | 
			
		||||
class TestApiRemoteVersion:
 | 
			
		||||
    ENDPOINT = "/api/remote_version/"
 | 
			
		||||
 | 
			
		||||
    def setup_method(self):
 | 
			
		||||
        cache.clear()
 | 
			
		||||
 | 
			
		||||
    def test_remote_version_enabled_no_update_prefix(
 | 
			
		||||
        self,
 | 
			
		||||
        rest_api_client: APIClient,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import re
 | 
			
		||||
import tempfile
 | 
			
		||||
import zipfile
 | 
			
		||||
from collections import defaultdict
 | 
			
		||||
from collections import deque
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from time import mktime
 | 
			
		||||
@@ -50,6 +51,7 @@ from django.utils.timezone import make_aware
 | 
			
		||||
from django.utils.translation import get_language
 | 
			
		||||
from django.views import View
 | 
			
		||||
from django.views.decorators.cache import cache_control
 | 
			
		||||
from django.views.decorators.cache import cache_page
 | 
			
		||||
from django.views.decorators.http import condition
 | 
			
		||||
from django.views.decorators.http import last_modified
 | 
			
		||||
from django.views.generic import TemplateView
 | 
			
		||||
@@ -69,6 +71,7 @@ from rest_framework import parsers
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
from rest_framework.decorators import action
 | 
			
		||||
from rest_framework.exceptions import NotFound
 | 
			
		||||
from rest_framework.exceptions import ValidationError
 | 
			
		||||
from rest_framework.filters import OrderingFilter
 | 
			
		||||
from rest_framework.filters import SearchFilter
 | 
			
		||||
from rest_framework.generics import GenericAPIView
 | 
			
		||||
@@ -1362,6 +1365,13 @@ class UnifiedSearchViewSet(DocumentViewSet):
 | 
			
		||||
                type=OpenApiTypes.STR,
 | 
			
		||||
                location=OpenApiParameter.PATH,
 | 
			
		||||
            ),
 | 
			
		||||
            OpenApiParameter(
 | 
			
		||||
                name="limit",
 | 
			
		||||
                type=OpenApiTypes.INT,
 | 
			
		||||
                location=OpenApiParameter.QUERY,
 | 
			
		||||
                description="Return only the last N entries from the log file",
 | 
			
		||||
                required=False,
 | 
			
		||||
            ),
 | 
			
		||||
        ],
 | 
			
		||||
        responses={
 | 
			
		||||
            (200, "application/json"): serializers.ListSerializer(
 | 
			
		||||
@@ -1393,8 +1403,22 @@ class LogViewSet(ViewSet):
 | 
			
		||||
        if not log_file.is_file():
 | 
			
		||||
            raise Http404
 | 
			
		||||
 | 
			
		||||
        limit_param = request.query_params.get("limit")
 | 
			
		||||
        if limit_param is not None:
 | 
			
		||||
            try:
 | 
			
		||||
                limit = int(limit_param)
 | 
			
		||||
            except (TypeError, ValueError):
 | 
			
		||||
                raise ValidationError({"limit": "Must be a positive integer"})
 | 
			
		||||
            if limit < 1:
 | 
			
		||||
                raise ValidationError({"limit": "Must be a positive integer"})
 | 
			
		||||
        else:
 | 
			
		||||
            limit = None
 | 
			
		||||
 | 
			
		||||
        with log_file.open() as f:
 | 
			
		||||
            lines = [line.rstrip() for line in f.readlines()]
 | 
			
		||||
            if limit is None:
 | 
			
		||||
                lines = [line.rstrip() for line in f.readlines()]
 | 
			
		||||
            else:
 | 
			
		||||
                lines = [line.rstrip() for line in deque(f, maxlen=limit)]
 | 
			
		||||
 | 
			
		||||
        return Response(lines)
 | 
			
		||||
 | 
			
		||||
@@ -2402,6 +2426,7 @@ class UiSettingsView(GenericAPIView):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@method_decorator(cache_page(60 * 15), name="dispatch")
 | 
			
		||||
@extend_schema_view(
 | 
			
		||||
    get=extend_schema(
 | 
			
		||||
        description="Get the current version of the Paperless-NGX server",
 | 
			
		||||
 
 | 
			
		||||
@@ -54,8 +54,8 @@ class TestCustomAccountAdapter(TestCase):
 | 
			
		||||
            # False because request host is not in allowed hosts
 | 
			
		||||
            self.assertFalse(adapter.is_safe_url(url))
 | 
			
		||||
 | 
			
		||||
    @mock.patch("allauth.core.internal.ratelimit.consume", return_value=True)
 | 
			
		||||
    def test_pre_authenticate(self, mock_consume):
 | 
			
		||||
    @mock.patch("allauth.core.ratelimit._consume_rate", return_value=True)
 | 
			
		||||
    def test_pre_authenticate(self, mock_consume_rate):
 | 
			
		||||
        adapter = get_adapter()
 | 
			
		||||
        request = HttpRequest()
 | 
			
		||||
        request.get_host = mock.Mock(return_value="example.com")
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,15 @@ class TestUrlCanary:
 | 
			
		||||
    Verify certain URLs are still available so testing is valid still
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    # Wikimedia rejects requests without a browser-like User-Agent header and returns 403.
 | 
			
		||||
    _WIKIMEDIA_HEADERS = {
 | 
			
		||||
        "User-Agent": (
 | 
			
		||||
            "Mozilla/5.0 (X11; Linux x86_64) "
 | 
			
		||||
            "AppleWebKit/537.36 (KHTML, like Gecko) "
 | 
			
		||||
            "Chrome/123.0.0.0 Safari/537.36"
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def test_online_image_exception_on_not_available(self):
 | 
			
		||||
        """
 | 
			
		||||
        GIVEN:
 | 
			
		||||
@@ -70,6 +79,7 @@ class TestUrlCanary:
 | 
			
		||||
        with pytest.raises(httpx.HTTPStatusError) as exec_info:
 | 
			
		||||
            resp = httpx.get(
 | 
			
		||||
                "https://upload.wikimedia.org/wikipedia/en/f/f7/nonexistent.png",
 | 
			
		||||
                headers=self._WIKIMEDIA_HEADERS,
 | 
			
		||||
            )
 | 
			
		||||
            resp.raise_for_status()
 | 
			
		||||
 | 
			
		||||
@@ -90,7 +100,10 @@ class TestUrlCanary:
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        # Now check the URL used in samples/sample.html
 | 
			
		||||
        resp = httpx.get("https://upload.wikimedia.org/wikipedia/en/f/f7/RickRoll.png")
 | 
			
		||||
        resp = httpx.get(
 | 
			
		||||
            "https://upload.wikimedia.org/wikipedia/en/f/f7/RickRoll.png",
 | 
			
		||||
            headers=self._WIKIMEDIA_HEADERS,
 | 
			
		||||
        )
 | 
			
		||||
        resp.raise_for_status()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								uv.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										21
									
								
								uv.lock
									
									
									
										generated
									
									
									
								
							@@ -689,13 +689,13 @@ wheels = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "django-allauth"
 | 
			
		||||
version = "65.12.1"
 | 
			
		||||
version = "65.4.1"
 | 
			
		||||
source = { registry = "https://pypi.org/simple" }
 | 
			
		||||
dependencies = [
 | 
			
		||||
    { name = "asgiref", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
    { name = "django", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
]
 | 
			
		||||
sdist = { url = "https://files.pythonhosted.org/packages/52/94/75d7f8c59e061d1b66a6d917b287817fe02d2671c9e6376a4ddfb3954989/django_allauth-65.12.1.tar.gz", hash = "sha256:662666ff2d5c71766f66b1629ac7345c30796813221184e13e11ed7460940c6a", size = 1967971, upload-time = "2025-10-16T16:39:58.342Z" }
 | 
			
		||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/e7/b3232c27da9f43e3db72d16addd90891ee233fa058ddd0588bafcded2ea7/django_allauth-65.4.1.tar.gz", hash = "sha256:60b32aef7dbbcc213319aa4fd8f570e985266ea1162ae6ef7a26a24efca85c8c", size = 1558220, upload-time = "2025-02-07T09:35:18.359Z" }
 | 
			
		||||
 | 
			
		||||
[package.optional-dependencies]
 | 
			
		||||
mfa = [
 | 
			
		||||
@@ -703,9 +703,9 @@ mfa = [
 | 
			
		||||
    { name = "qrcode", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
]
 | 
			
		||||
socialaccount = [
 | 
			
		||||
    { name = "oauthlib", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
    { name = "pyjwt", extra = ["crypto"], marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
    { name = "requests", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
    { name = "requests-oauthlib", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2262,7 +2262,7 @@ requires-dist = [
 | 
			
		||||
    { name = "concurrent-log-handler", specifier = "~=0.9.25" },
 | 
			
		||||
    { name = "dateparser", specifier = "~=1.2" },
 | 
			
		||||
    { name = "django", specifier = "~=5.2.5" },
 | 
			
		||||
    { name = "django-allauth", extras = ["mfa", "socialaccount"], specifier = "~=65.12.1" },
 | 
			
		||||
    { name = "django-allauth", extras = ["mfa", "socialaccount"], specifier = "~=65.4.0" },
 | 
			
		||||
    { name = "django-auditlog", specifier = "~=3.2.1" },
 | 
			
		||||
    { name = "django-cachalot", specifier = "~=2.8.0" },
 | 
			
		||||
    { name = "django-celery-results", specifier = "~=2.6.0" },
 | 
			
		||||
@@ -3379,6 +3379,19 @@ wheels = [
 | 
			
		||||
    { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "requests-oauthlib"
 | 
			
		||||
version = "2.0.0"
 | 
			
		||||
source = { registry = "https://pypi.org/simple" }
 | 
			
		||||
dependencies = [
 | 
			
		||||
    { name = "oauthlib", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
    { name = "requests", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
 | 
			
		||||
]
 | 
			
		||||
sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" }
 | 
			
		||||
wheels = [
 | 
			
		||||
    { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rich"
 | 
			
		||||
version = "14.1.0"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user