diff --git a/renderers/react/a2ui_explorer/README.md b/renderers/react/a2ui_explorer/README.md index 2b04a3e15..26341a814 100644 --- a/renderers/react/a2ui_explorer/README.md +++ b/renderers/react/a2ui_explorer/README.md @@ -25,35 +25,40 @@ npm run build ## Setup and Development -Once the dependencies are built, you can start the gallery app: +Once the dependencies are built, you can start the gallery app from the parent directory: ```bash -# Navigate to this directory -cd renderers/react/a2ui_explorer +# Navigate to the React renderer directory +cd renderers/react -# Install dependencies -npm install - -# Start the development server -npm run dev +# Start the gallery app (Vite) +npm run demo ``` + ## Building for Production -To create a production build of the gallery app: +To create a production build of the gallery app, run the following from the parent directory: ```bash -npm run build +# Navigate to the React renderer directory +cd renderers/react + +npm run build:demo ``` ## Running Tests -To run the integration tests: +To run the integration tests for the gallery app, run the following from the parent directory: ```bash -npm test +# Navigate to the React renderer directory +cd renderers/react + +npm run test:demo ``` + ## Gallery Features - **3-Column Layout**: Left (Sample selection), Center (Live preview & Message stepper), Right (Data model & Action logs). diff --git a/renderers/react/a2ui_explorer/src/App.tsx b/renderers/react/a2ui_explorer/src/App.tsx index f321c5034..58947448a 100644 --- a/renderers/react/a2ui_explorer/src/App.tsx +++ b/renderers/react/a2ui_explorer/src/App.tsx @@ -16,10 +16,10 @@ import {useState, useEffect, useSyncExternalStore, useCallback} from 'react'; import {MessageProcessor, SurfaceModel} from '@a2ui/web_core/v0_9'; -import {minimalCatalog, basicCatalog, A2uiSurface, type ReactComponentImplementation} from '@a2ui/react/v0_9'; +import {minimalCatalog, basicCatalog, A2uiSurface, reactSignal, type ReactComponentImplementation} from '@a2ui/react/v0_9'; import {exampleFiles, getMessages} from './examples'; -const DataModelViewer = ({surface}: {surface: SurfaceModel}) => { +const DataModelViewer = ({surface}: {surface: SurfaceModel;}) => { const subscribeHook = useCallback( (callback: () => void) => { const bound = surface.dataModel.subscribe('/', callback); @@ -47,7 +47,7 @@ export default function App() { const selectedExample = exampleFiles.find((e) => e.key === selectedExampleKey)?.data as any; const [logs, setLogs] = useState([]); - const [processor, setProcessor] = useState | null>(null); + const [processor, setProcessor] = useState | null>(null); const [surfaces, setSurfaces] = useState([]); const [currentMessageIndex, setCurrentMessageIndex] = useState(-1); @@ -58,7 +58,7 @@ export default function App() { if (prevProcessor) { prevProcessor.model.dispose(); } - const newProcessor = new MessageProcessor([minimalCatalog, basicCatalog], async (action: any) => { + const newProcessor = new MessageProcessor([minimalCatalog, basicCatalog], reactSignal, async (action: any) => { setLogs((l) => [...l, {time: new Date().toISOString(), action}]); }); diff --git a/renderers/react/a2ui_explorer/src/integration.test.tsx b/renderers/react/a2ui_explorer/src/integration.test.tsx index 0f142d0da..a2490e33b 100644 --- a/renderers/react/a2ui_explorer/src/integration.test.tsx +++ b/renderers/react/a2ui_explorer/src/integration.test.tsx @@ -18,7 +18,7 @@ import {describe, it, expect} from 'vitest'; import {render, screen, act, fireEvent} from '@testing-library/react'; import React from 'react'; import {MessageProcessor} from '@a2ui/web_core/v0_9'; -import {A2uiSurface, minimalCatalog} from '@a2ui/react/v0_9'; +import {A2uiSurface, minimalCatalog, reactSignal} from '@a2ui/react/v0_9'; import ex1 from '../../../../specification/v0_9/json/catalogs/minimal/examples/1_simple_text.json'; import ex2 from '../../../../specification/v0_9/json/catalogs/minimal/examples/2_row_layout.json'; @@ -26,7 +26,7 @@ import ex4 from '../../../../specification/v0_9/json/catalogs/minimal/examples/4 describe('Gallery Integration Tests', () => { it('renders Simple Text -> "Hello Minimal Catalog"', async () => { - const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + const processor = new MessageProcessor([minimalCatalog as any], reactSignal, async () => {}); processor.processMessages(ex1.messages as any[]); const surface = processor.model.getSurface('example_1'); @@ -42,7 +42,7 @@ describe('Gallery Integration Tests', () => { }); it('renders Row layout -> content visibility', async () => { - const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + const processor = new MessageProcessor([minimalCatalog as any], reactSignal, async () => {}); processor.processMessages(ex2.messages as any[]); const surface = processor.model.getSurface('example_2'); @@ -59,7 +59,7 @@ describe('Gallery Integration Tests', () => { }); it('handles Login form -> input updates data model', async () => { - const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + const processor = new MessageProcessor([minimalCatalog as any], reactSignal, async () => {}); processor.processMessages(ex4.messages as any[]); const surface = processor.model.getSurface('example_4'); diff --git a/renderers/react/package-lock.json b/renderers/react/package-lock.json index e107fc4f1..66e484fc6 100644 --- a/renderers/react/package-lock.json +++ b/renderers/react/package-lock.json @@ -1,15 +1,15 @@ { "name": "@a2ui/react", - "version": "0.8.1", + "version": "0.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@a2ui/react", - "version": "0.8.1", - "license": "Apache-2.0", + "version": "0.9.0", "dependencies": { "@a2ui/web_core": "file:../web_core", + "@preact/signals-core": "^1.13.0", "clsx": "^2.1.0", "markdown-it": "^14.0.0", "zod": "^3.23.8" @@ -51,28 +51,9 @@ "zod": "^3.23.8" } }, - "../lit": { - "name": "@a2ui/lit", - "version": "0.8.1", - "extraneous": true, - "license": "Apache-2.0", - "dependencies": { - "@a2ui/web_core": "file:../web_core", - "@lit-labs/signals": "^0.1.3", - "@lit/context": "^1.1.4", - "lit": "^3.3.1", - "signal-utils": "^0.21.1" - }, - "devDependencies": { - "@types/node": "^24.10.1", - "google-artifactregistry-auth": "^3.5.0", - "typescript": "^5.8.3", - "wireit": "^0.15.0-pre.2" - } - }, "../web_core": { "name": "@a2ui/web_core", - "version": "0.8.8", + "version": "0.9.1", "license": "Apache-2.0", "dependencies": { "@preact/signals-core": "^1.13.0", @@ -84,9 +65,10 @@ "@angular/core": "^21.2.5", "@types/node": "^24.11.0", "c8": "^11.0.0", + "google-artifactregistry-auth": "^3.5.0", "gts": "^7.0.0", "rxjs": "^7.8.2", - "typescript": "^5.8.3", + "typescript": "^5.9.3", "wireit": "^0.15.0-pre.2" } }, @@ -107,21 +89,33 @@ "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "5.1.1", + "integrity": "sha512-iGWN8E45Ws0XWx3D44Q1t6vX2LqhCKcwfmwBYCDsFrYFS6m4q/Ks61L2veETaLv+ckDC6+dTETJoaAAb7VjLiw==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.1.1", + "@csstools/css-color-parser": "^4.0.2", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.7" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.2.7", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.7", - "integrity": "sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA==", + "version": "6.8.1", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -129,7 +123,16 @@ "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.5" + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.2.7", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/@asamuzakjp/nwsapi": { @@ -223,21 +226,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", @@ -372,8 +360,8 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.2", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "dev": true, "license": "MIT", "engines": { @@ -425,9 +413,21 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.2", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -441,12 +441,12 @@ ], "license": "MIT-0", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "version": "3.1.1", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", "dev": true, "funding": [ { @@ -460,16 +460,16 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "version": "4.0.2", + "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", "dev": true, "funding": [ { @@ -483,20 +483,20 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.1.1" }, "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "version": "4.0.0", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -510,15 +510,15 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.26", - "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==", + "version": "1.1.2", + "integrity": "sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==", "dev": true, "funding": [ { @@ -530,11 +530,19 @@ "url": "https://opencollective.com/csstools" } ], - "license": "MIT-0" + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -548,12 +556,12 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "version": "0.27.7", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -568,8 +576,8 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "version": "0.27.7", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -584,8 +592,8 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "version": "0.27.7", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -600,8 +608,8 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "version": "0.27.7", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -616,8 +624,8 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "version": "0.27.7", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -632,8 +640,8 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "version": "0.27.7", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -648,8 +656,8 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.27.7", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -664,8 +672,8 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.27.7", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -680,8 +688,8 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "version": "0.27.7", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -696,8 +704,8 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "version": "0.27.7", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -712,8 +720,8 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "version": "0.27.7", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -728,8 +736,8 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "version": "0.27.7", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -744,8 +752,8 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "version": "0.27.7", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -760,8 +768,8 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "version": "0.27.7", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -776,8 +784,8 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.27.7", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -792,8 +800,8 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.27.7", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -808,8 +816,8 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "version": "0.27.7", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -824,8 +832,8 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "version": "0.27.7", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -840,8 +848,8 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "version": "0.27.7", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -856,8 +864,8 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "version": "0.27.7", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -872,8 +880,8 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "version": "0.27.7", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -888,8 +896,8 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "version": "0.27.7", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -904,8 +912,8 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "version": "0.27.7", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -920,8 +928,8 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "version": "0.27.7", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -936,8 +944,8 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "version": "0.27.7", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -952,8 +960,8 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "version": "0.27.7", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -1007,14 +1015,14 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.21.2", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1045,19 +1053,19 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "version": "3.3.5", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -1080,8 +1088,8 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "version": "9.39.4", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -1114,8 +1122,8 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.11.0", - "integrity": "sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==", + "version": "1.15.0", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", "dev": true, "license": "MIT", "engines": { @@ -1235,6 +1243,15 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@preact/signals-core": { + "version": "1.14.1", + "integrity": "sha512-vxPpfXqrwUe9lpjqfYNjAF/0RF/eFGeLgdJzdmIIZjpOnTmGmAB4BjWone562mJGMRP4frU6iZ6ei3PDsu52Ng==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/@puppeteer/browsers": { "version": "2.13.0", "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", @@ -1275,8 +1292,8 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.60.1", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", "cpu": [ "arm" ], @@ -1288,8 +1305,8 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.60.1", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", "cpu": [ "arm64" ], @@ -1301,8 +1318,8 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.60.1", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", "cpu": [ "arm64" ], @@ -1314,8 +1331,8 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.60.1", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", "cpu": [ "x64" ], @@ -1327,8 +1344,8 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.60.1", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", "cpu": [ "arm64" ], @@ -1340,8 +1357,8 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.60.1", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", "cpu": [ "x64" ], @@ -1353,8 +1370,8 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.60.1", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", "cpu": [ "arm" ], @@ -1366,8 +1383,8 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.60.1", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", "cpu": [ "arm" ], @@ -1379,8 +1396,8 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.60.1", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", "cpu": [ "arm64" ], @@ -1392,8 +1409,8 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.60.1", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", "cpu": [ "arm64" ], @@ -1405,8 +1422,8 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.60.1", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", "cpu": [ "loong64" ], @@ -1418,8 +1435,8 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.60.1", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", "cpu": [ "loong64" ], @@ -1431,8 +1448,8 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.60.1", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", "cpu": [ "ppc64" ], @@ -1444,8 +1461,8 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.60.1", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", "cpu": [ "ppc64" ], @@ -1457,8 +1474,8 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.60.1", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", "cpu": [ "riscv64" ], @@ -1470,8 +1487,8 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.60.1", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", "cpu": [ "riscv64" ], @@ -1483,8 +1500,8 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.60.1", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", "cpu": [ "s390x" ], @@ -1496,8 +1513,8 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.60.1", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", "cpu": [ "x64" ], @@ -1509,8 +1526,8 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.60.1", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", "cpu": [ "x64" ], @@ -1522,8 +1539,8 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.60.1", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", "cpu": [ "x64" ], @@ -1535,8 +1552,8 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.60.1", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", "cpu": [ "arm64" ], @@ -1548,8 +1565,8 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.60.1", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", "cpu": [ "arm64" ], @@ -1561,8 +1578,8 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.60.1", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", "cpu": [ "ia32" ], @@ -1574,8 +1591,8 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.60.1", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", "cpu": [ "x64" ], @@ -1587,8 +1604,8 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.60.1", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", "cpu": [ "x64" ], @@ -1809,8 +1826,8 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.27", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "version": "18.3.28", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "dev": true, "license": "MIT", "dependencies": { @@ -1838,19 +1855,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.54.0", - "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "version": "8.58.0", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/type-utils": "8.54.0", - "@typescript-eslint/utils": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1860,9 +1877,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.54.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -1875,15 +1892,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.54.0", - "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "version": "8.58.0", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3" }, "engines": { @@ -1894,18 +1911,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.58.0", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "engines": { @@ -1916,17 +1933,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.58.0", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1937,8 +1954,8 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.58.0", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, "license": "MIT", "engines": { @@ -1949,20 +1966,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.54.0", - "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "version": "8.58.0", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1972,13 +1989,13 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.58.0", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", "dev": true, "license": "MIT", "engines": { @@ -1990,20 +2007,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.58.0", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2013,36 +2030,48 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.5", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.2.5", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -2053,15 +2082,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.58.0", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2071,18 +2100,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.58.0", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2092,6 +2121,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@vitejs/plugin-react": { "version": "5.2.0", "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", @@ -2113,29 +2154,29 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.18", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "version": "4.1.2", + "integrity": "sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.2", + "@vitest/utils": "4.1.2", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.0.18", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "version": "4.1.2", + "integrity": "sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.2", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -2144,7 +2185,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -2156,24 +2197,24 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "version": "4.1.2", + "integrity": "sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.0.18", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "version": "4.1.2", + "integrity": "sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.2", "pathe": "^2.0.3" }, "funding": { @@ -2181,12 +2222,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "version": "4.1.2", + "integrity": "sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.2", + "@vitest/utils": "4.1.2", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -2195,8 +2237,8 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.18", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "version": "4.1.2", + "integrity": "sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==", "dev": true, "license": "MIT", "funding": { @@ -2204,21 +2246,22 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.18", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "version": "4.1.2", + "integrity": "sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.2", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/acorn": { - "version": "8.15.0", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -2247,8 +2290,8 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2287,13 +2330,15 @@ } }, "node_modules/ansi-styles": { - "version": "5.2.0", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -2525,8 +2570,8 @@ } }, "node_modules/bare-fs": { - "version": "4.5.6", - "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==", + "version": "4.6.0", + "integrity": "sha512-2YkS7NuiJceSEbyEOdSNLE9tsGd+f4+f7C+Nik/MCk27SYdwIMPT/yRKvg++FZhQXgk0KWJKJyXX9RhVV0RGqA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2549,8 +2594,8 @@ } }, "node_modules/bare-os": { - "version": "3.8.0", - "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==", + "version": "3.8.7", + "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2567,8 +2612,8 @@ } }, "node_modules/bare-stream": { - "version": "2.10.0", - "integrity": "sha512-DOPZF/DDcDruKDA43cOw6e9Quq5daua7ygcAwJE/pKJsRWhgSSemi7qVNGE5kyDIxIeN1533G/zfbvWX7Wcb9w==", + "version": "2.12.0", + "integrity": "sha512-w28i8lkBgREV3rPXGbgK+BO66q+ZpKqRWrZLiCdmmUlLPrQ45CzkvRhN+7lnv00Gpi2zy5naRxnUFAxCECDm9g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2576,10 +2621,14 @@ "teex": "^1.0.1" }, "peerDependencies": { + "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, "bare-buffer": { "optional": true }, @@ -2598,8 +2647,8 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.9", - "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==", + "version": "2.10.13", + "integrity": "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2628,8 +2677,8 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2638,8 +2687,8 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -2657,11 +2706,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -2786,8 +2835,8 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001780", - "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "version": "1.0.30001784", + "integrity": "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==", "dev": true, "funding": [ { @@ -2830,21 +2879,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/chardet": { "version": "0.7.0", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", @@ -3017,13 +3051,13 @@ } }, "node_modules/css-tree": { - "version": "3.1.0", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" @@ -3036,20 +3070,29 @@ "license": "MIT" }, "node_modules/cssstyle": { - "version": "5.3.7", - "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "version": "6.2.0", + "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "@asamuzakjp/css-color": "^5.0.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", "css-tree": "^3.1.0", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" }, "engines": { "node": ">=20" } }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.2.7", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/csstype": { "version": "3.2.3", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", @@ -3289,8 +3332,8 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.321", - "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "version": "1.5.331", + "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==", "dev": true, "license": "ISC" }, @@ -3310,8 +3353,8 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.20.0", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "version": "5.20.1", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "dev": true, "license": "MIT", "dependencies": { @@ -3438,8 +3481,8 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.2.2", - "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "version": "1.3.1", + "integrity": "sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3458,6 +3501,7 @@ "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0", "safe-array-concat": "^1.1.3" }, "engines": { @@ -3465,8 +3509,8 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -3527,8 +3571,8 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "version": "0.27.7", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3539,32 +3583,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/escalade": { @@ -3609,35 +3653,25 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint": { - "version": "9.39.2", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "9.39.4", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", + "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", @@ -3656,7 +3690,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -4206,8 +4240,8 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -4372,8 +4406,8 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.6", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "version": "4.13.7", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4614,6 +4648,12 @@ "node": ">=10" } }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", @@ -4698,15 +4738,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", @@ -4749,24 +4780,6 @@ "node": ">=8.0.0" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "6.6.7", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/inquirer/node_modules/tslib": { - "version": "1.14.1", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/internal-slot": { "version": "1.1.0", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", @@ -5247,15 +5260,16 @@ } }, "node_modules/jsdom": { - "version": "28.0.0", - "integrity": "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==", + "version": "28.1.0", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", "dev": true, "license": "MIT", "dependencies": { "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.7.6", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", "@exodus/bytes": "^1.11.0", - "cssstyle": "^5.3.7", + "cssstyle": "^6.0.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", @@ -5266,7 +5280,7 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", - "undici": "^7.20.0", + "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", @@ -5430,8 +5444,8 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, @@ -5454,12 +5468,12 @@ } }, "node_modules/lru-cache": { - "version": "11.2.5", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "5.1.1", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/lz-string": { @@ -5494,8 +5508,8 @@ } }, "node_modules/markdown-it": { - "version": "14.1.0", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "version": "14.1.1", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1", @@ -5519,8 +5533,8 @@ } }, "node_modules/mdn-data": { - "version": "2.12.2", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.27.1", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, "license": "CC0-1.0" }, @@ -5592,8 +5606,8 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -5624,15 +5638,15 @@ "license": "MIT" }, "node_modules/mlly": { - "version": "1.8.0", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.8.2", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" } }, "node_modules/ms": { @@ -5700,9 +5714,27 @@ "node": ">= 0.4.0" } }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/node-releases": { - "version": "2.0.36", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "version": "2.0.37", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", "dev": true, "license": "MIT" }, @@ -6091,8 +6123,8 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -6132,8 +6164,8 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -6252,6 +6284,19 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/progress": { "version": "2.0.3", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", @@ -6664,29 +6709,35 @@ } }, "node_modules/resolve": { - "version": "2.0.0-next.5", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "version": "2.0.0-next.6", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { - "version": "5.0.0", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "version": "4.0.0", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/resolve-pkg-maps": { @@ -6712,8 +6763,8 @@ } }, "node_modules/rollup": { - "version": "4.57.1", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.60.1", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", "dependencies": { @@ -6727,31 +6778,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" } }, @@ -6764,6 +6815,24 @@ "node": ">=0.12.0" } }, + "node_modules/rxjs": { + "version": "6.6.7", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/safe-array-concat": { "version": "1.1.3", "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", @@ -7042,12 +7111,13 @@ } }, "node_modules/source-map": { - "version": "0.7.6", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "version": "0.6.1", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", + "optional": true, "engines": { - "node": ">= 12" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -7098,8 +7168,8 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "3.10.0", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.0.0", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", "dev": true, "license": "MIT" }, @@ -7347,8 +7417,8 @@ } }, "node_modules/tapable": { - "version": "2.3.0", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.2", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", "dev": true, "license": "MIT", "engines": { @@ -7487,8 +7557,8 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.0", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -7496,20 +7566,20 @@ } }, "node_modules/tldts": { - "version": "7.0.21", - "integrity": "sha512-Plu6V8fF/XU6d2k8jPtlQf5F4Xx2hAin4r2C2ca7wR8NK5MbRTo9huLUWRe28f3Uk8bYZfg74tit/dSjc18xnw==", + "version": "7.0.27", + "integrity": "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.21" + "tldts-core": "^7.0.27" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.21", - "integrity": "sha512-oVOMdHvgjqyzUZH1rOESgJP1uNe2bVrfK0jUHHmiM2rpEiRbf3j4BrsIc6JigJRbHGanQwuZv/R+LTcHsw+bLA==", + "version": "7.0.27", + "integrity": "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==", "dev": true, "license": "MIT" }, @@ -7526,8 +7596,8 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.0", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "version": "6.0.1", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -7568,8 +7638,8 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -7665,6 +7735,24 @@ } } }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.7.6", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/tsx": { "version": "4.21.0", "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", @@ -7802,15 +7890,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.54.0", - "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", + "version": "8.58.0", + "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.54.0", - "@typescript-eslint/parser": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0" + "@typescript-eslint/eslint-plugin": "8.58.0", + "@typescript-eslint/parser": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7820,8 +7908,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/uc.micro": { @@ -7854,8 +7942,8 @@ } }, "node_modules/undici": { - "version": "7.20.0", - "integrity": "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==", + "version": "7.24.7", + "integrity": "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==", "dev": true, "license": "MIT", "engines": { @@ -7992,30 +8080,30 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "version": "4.1.2", + "integrity": "sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "@vitest/expect": "4.1.2", + "@vitest/mocker": "4.1.2", + "@vitest/pretty-format": "4.1.2", + "@vitest/runner": "4.1.2", + "@vitest/snapshot": "4.1.2", + "@vitest/spy": "4.1.2", + "@vitest/utils": "4.1.2", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -8031,12 +8119,13 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", + "@vitest/browser-playwright": "4.1.2", + "@vitest/browser-preview": "4.1.2", + "@vitest/browser-webdriverio": "4.1.2", + "@vitest/ui": "4.1.2", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -8065,12 +8154,15 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, "node_modules/vitest/node_modules/tinyexec": { - "version": "1.0.2", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.0.4", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", "dev": true, "license": "MIT", "engines": { @@ -8114,8 +8206,8 @@ } }, "node_modules/whatwg-url": { - "version": "16.0.0", - "integrity": "sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==", + "version": "16.0.1", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "license": "MIT", "dependencies": { @@ -8269,21 +8361,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", @@ -8316,8 +8393,8 @@ } }, "node_modules/ws": { - "version": "8.19.0", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "dev": true, "license": "MIT", "engines": { @@ -8361,8 +8438,8 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, diff --git a/renderers/react/package.json b/renderers/react/package.json index 1d2771136..6bfc46d6f 100644 --- a/renderers/react/package.json +++ b/renderers/react/package.json @@ -91,6 +91,7 @@ }, "dependencies": { "@a2ui/web_core": "file:../web_core", + "@preact/signals-core": "^1.13.0", "clsx": "^2.1.0", "markdown-it": "^14.0.0", "zod": "^3.23.8" diff --git a/renderers/react/src/v0_9/A2uiSurface.tsx b/renderers/react/src/v0_9/A2uiSurface.tsx index 125593371..d3955b3a9 100644 --- a/renderers/react/src/v0_9/A2uiSurface.tsx +++ b/renderers/react/src/v0_9/A2uiSurface.tsx @@ -17,6 +17,7 @@ import React, {useSyncExternalStore, memo, useMemo, useCallback} from 'react'; import {type SurfaceModel, ComponentContext, type ComponentModel} from '@a2ui/web_core/v0_9'; import type {ReactComponentImplementation} from './adapter'; +import {reactSignal} from './reactSignal'; const ResolvedChild = memo( ({ @@ -26,7 +27,7 @@ const ResolvedChild = memo( compImpl, componentModel, }: { - surface: SurfaceModel; + surface: SurfaceModel; id: string; basePath: string; componentModel: ComponentModel; @@ -34,9 +35,10 @@ const ResolvedChild = memo( }) => { const ComponentToRender = compImpl.render; - // Create context. Recreate if the componentModel instance changes (e.g. type change recreation). + // Create context. Recreate if the componentModel instance changes (e.g. + // type change recreation). const context = useMemo( - () => new ComponentContext(surface, id, basePath), + () => new ComponentContext(surface, id, reactSignal, basePath), // componentModel is used as a trigger for recreation even if not in the body // eslint-disable-next-line react-hooks/exhaustive-deps [surface, id, basePath, componentModel] @@ -63,7 +65,7 @@ const ResolvedChild = memo( ResolvedChild.displayName = 'ResolvedChild'; export const DeferredChild: React.FC<{ - surface: SurfaceModel; + surface: SurfaceModel; id: string; basePath: string; }> = memo(({surface, id, basePath}) => { @@ -124,9 +126,9 @@ export const DeferredChild: React.FC<{ }); DeferredChild.displayName = 'DeferredChild'; -export const A2uiSurface: React.FC<{surface: SurfaceModel}> = ({ - surface, -}) => { +export const A2uiSurface: React.FC<{ + surface: SurfaceModel; +}> = ({surface}) => { // The root component always has ID 'root' and base path '/' return ; }; diff --git a/renderers/react/src/v0_9/adapter.tsx b/renderers/react/src/v0_9/adapter.tsx index 5f42f667b..beb536858 100644 --- a/renderers/react/src/v0_9/adapter.tsx +++ b/renderers/react/src/v0_9/adapter.tsx @@ -25,7 +25,7 @@ import type { export interface ReactComponentImplementation extends ComponentApi { /** The framework-specific rendering wrapper. */ render: React.FC<{ - context: ComponentContext; + context: ComponentContext<'react'>; buildChild: (id: string, basePath?: string) => React.ReactNode; }>; } @@ -33,7 +33,7 @@ export interface ReactComponentImplementation extends ComponentApi { export type ReactA2uiComponentProps = { props: T; buildChild: (id: string, basePath?: string) => React.ReactNode; - context: ComponentContext; + context: ComponentContext<'react'>; }; // --- Component Factories --- @@ -57,19 +57,21 @@ export function createReactComponent( }); const ReactWrapper: React.FC<{ - context: ComponentContext; + context: ComponentContext<'react'>; buildChild: (id: string, basePath?: string) => React.ReactNode; }> = ({context, buildChild}) => { - const bindingRef = useRef | null>(null); + const bindingRef = useRef | null>(null); // Create or recreate the binder if the context object changes. // DeferredChild memoizes `context`, so reference changes strictly correspond // to ComponentModel updates (like type changes) or Base Path adjustments. if (!bindingRef.current) { - bindingRef.current = new GenericBinder(context, api.schema); - } else if ((bindingRef.current as unknown as {context: ComponentContext}).context !== context) { + bindingRef.current = new GenericBinder(context, api.schema); + } else if ( + (bindingRef.current as unknown as {context: ComponentContext<'react'>}).context !== context + ) { bindingRef.current.dispose(); - bindingRef.current = new GenericBinder(context, api.schema); + bindingRef.current = new GenericBinder(context, api.schema); } const binding = bindingRef.current; @@ -107,7 +109,7 @@ export function createReactComponent( export function createBinderlessComponent( api: ComponentApi, RenderComponent: React.FC<{ - context: ComponentContext; + context: ComponentContext<'react'>; buildChild: (id: string, basePath?: string) => React.ReactNode; }> ): ReactComponentImplementation { diff --git a/renderers/react/src/v0_9/catalog/basic/components/ChildList.tsx b/renderers/react/src/v0_9/catalog/basic/components/ChildList.tsx index 90dfe03e0..71f3c5e70 100644 --- a/renderers/react/src/v0_9/catalog/basic/components/ChildList.tsx +++ b/renderers/react/src/v0_9/catalog/basic/components/ChildList.tsx @@ -19,7 +19,7 @@ import {type ComponentContext} from '@a2ui/web_core/v0_9'; export const ChildList: React.FC<{ childList: unknown; - context: ComponentContext; + context: ComponentContext<'react'>; buildChild: (id: string, basePath?: string) => React.ReactNode; }> = ({childList, buildChild}) => { if (Array.isArray(childList)) { diff --git a/renderers/react/src/v0_9/catalog/basic/index.ts b/renderers/react/src/v0_9/catalog/basic/index.ts index d9c6e3306..761b8c990 100644 --- a/renderers/react/src/v0_9/catalog/basic/index.ts +++ b/renderers/react/src/v0_9/catalog/basic/index.ts @@ -16,7 +16,6 @@ import {Catalog} from '@a2ui/web_core/v0_9'; import {BASIC_FUNCTIONS} from '@a2ui/web_core/v0_9/basic_catalog'; -import type {ReactComponentImplementation} from '../../adapter'; import {Text} from './components/Text'; import {Image} from './components/Image'; @@ -36,6 +35,7 @@ import {CheckBox} from './components/CheckBox'; import {ChoicePicker} from './components/ChoicePicker'; import {Slider} from './components/Slider'; import {DateTimeInput} from './components/DateTimeInput'; +import type {ReactComponentImplementation} from '../../adapter'; const basicComponents: ReactComponentImplementation[] = [ Text, @@ -58,7 +58,7 @@ const basicComponents: ReactComponentImplementation[] = [ DateTimeInput, ]; -export const basicCatalog = new Catalog( +export const basicCatalog = new Catalog( 'https://a2ui.org/specification/v0_9/basic_catalog.json', basicComponents, BASIC_FUNCTIONS diff --git a/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx b/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx index b36c43221..73f081d40 100644 --- a/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx +++ b/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx @@ -14,10 +14,11 @@ * limitations under the License. */ -import {createReactComponent} from '../../../adapter'; import {z} from 'zod'; import {CommonSchemas} from '@a2ui/web_core/v0_9'; +import {createReactComponent} from '../../../adapter'; + export const TextSchema = z.object({ text: CommonSchemas.DynamicString, variant: z.enum(['h1', 'h2', 'h3', 'h4', 'h5', 'caption', 'body']).optional(), diff --git a/renderers/react/src/v0_9/catalog/minimal/index.ts b/renderers/react/src/v0_9/catalog/minimal/index.ts index 65fd769b0..befb31d42 100644 --- a/renderers/react/src/v0_9/catalog/minimal/index.ts +++ b/renderers/react/src/v0_9/catalog/minimal/index.ts @@ -15,17 +15,18 @@ */ import {Catalog, createFunctionImplementation} from '@a2ui/web_core/v0_9'; +import {z} from 'zod'; + import {Text} from './components/Text'; import {Button} from './components/Button'; import {Row} from './components/Row'; import {Column} from './components/Column'; import {TextField} from './components/TextField'; import type {ReactComponentImplementation} from '../../adapter'; -import {z} from 'zod'; const minimalComponents: ReactComponentImplementation[] = [Text, Button, Row, Column, TextField]; -export const minimalCatalog = new Catalog( +export const minimalCatalog = new Catalog( 'https://a2ui.org/specification/v0_9/catalogs/minimal/minimal_catalog.json', minimalComponents, [ diff --git a/renderers/react/src/v0_9/index.ts b/renderers/react/src/v0_9/index.ts index b4c1ee5fd..a46fbfc1a 100644 --- a/renderers/react/src/v0_9/index.ts +++ b/renderers/react/src/v0_9/index.ts @@ -16,6 +16,7 @@ export * from './A2uiSurface'; export * from './adapter'; +export * from './reactSignal'; // Export basic catalog components directly for 3P developers export * from './catalog/basic'; diff --git a/renderers/react/src/v0_9/reactSignal.ts b/renderers/react/src/v0_9/reactSignal.ts new file mode 100644 index 000000000..90a72a34a --- /dev/null +++ b/renderers/react/src/v0_9/reactSignal.ts @@ -0,0 +1,23 @@ +import {type FrameworkSignal} from '@a2ui/web_core/v0_9'; +import {Signal, computed, effect} from '@preact/signals-core'; + +declare module '@a2ui/web_core/v0_9' { + interface SignalKinds { + react: Signal; + } + interface WritableSignalKinds { + react: Signal; + } +} + +/** + * A FrameworkSignal implementation that wraps Preact signals. + */ +export const reactSignal: FrameworkSignal<'react'> = { + computed: (fn: () => T) => computed(fn), + isSignal: (val: unknown) => val instanceof Signal, + wrap: (val: T) => new Signal(val), + unwrap: (val: Signal) => val.value, + set: (signal: Signal, value: T) => (signal.value = value), + effect: (fn: () => void) => effect(fn), +}; diff --git a/renderers/react/tests/utils.tsx b/renderers/react/tests/utils.tsx index 292e31c37..7fb687fcc 100644 --- a/renderers/react/tests/utils.tsx +++ b/renderers/react/tests/utils.tsx @@ -15,11 +15,12 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; -import { vi } from 'vitest'; -import { SurfaceModel, ComponentModel, Catalog, ComponentContext } from '@a2ui/web_core/v0_9'; -import { BASIC_FUNCTIONS } from '@a2ui/web_core/v0_9/basic_catalog'; -import type { ReactComponentImplementation } from '../src/v0_9/adapter'; +import {render} from '@testing-library/react'; +import {vi} from 'vitest'; +import {SurfaceModel, ComponentModel, Catalog, ComponentContext} from '@a2ui/web_core/v0_9'; +import {BASIC_FUNCTIONS} from '@a2ui/web_core/v0_9/basic_catalog'; +import type {ReactComponentImplementation} from '../src/v0_9/adapter'; +import {reactSignal} from '../src/v0_9/reactSignal'; export interface RenderA2uiOptions { initialData?: Record; @@ -41,9 +42,9 @@ export function renderA2uiComponent( initialProperties: Record, options: RenderA2uiOptions = {} ) { - const { - initialData = {}, - additionalImpls = [], + const { + initialData = {}, + additionalImpls = [], additionalComponents = [], functions = BASIC_FUNCTIONS } = options; @@ -51,8 +52,8 @@ export function renderA2uiComponent( // Combine all implementations into the catalog const allImpls = [impl, ...additionalImpls]; const catalog = new Catalog('test-catalog', allImpls, functions); - const surface = new SurfaceModel('test-surface', catalog); - + const surface = new SurfaceModel('test-surface', catalog, reactSignal); + // Setup data model surface.dataModel.set('/', initialData); @@ -65,24 +66,24 @@ export function renderA2uiComponent( surface.componentsModel.addComponent(childModel); } - const mainContext = new ComponentContext(surface, componentId, '/'); + const mainContext = new ComponentContext(surface, componentId, reactSignal, '/'); // Smart buildChild mock: // 1. If the component exists in the model and catalog, render it for real. // 2. Otherwise, render a placeholder div that tests can query. const buildChild = vi.fn((id: string, basePath?: string) => { const compModel = surface.componentsModel.get(id); - + if (!compModel) { return
; } const compImpl = surface.catalog.components.get(compModel.type); if (!compImpl) { - return
; + return
; } - const ctx = new ComponentContext(surface, id, basePath || '/'); + const ctx = new ComponentContext(surface, id, reactSignal, basePath || '/'); const ChildComponent = (compImpl as ReactComponentImplementation).render; return ; @@ -94,10 +95,10 @@ export function renderA2uiComponent( ); - return { - view, - surface, - buildChild, + return { + view, + surface, + buildChild, mainModel, context: mainContext, // Helper to trigger data model updates and wait for re-render diff --git a/renderers/react/tests/v0_9/adapter.test.tsx b/renderers/react/tests/v0_9/adapter.test.tsx index bd9ef03a1..7f0a45936 100644 --- a/renderers/react/tests/v0_9/adapter.test.tsx +++ b/renderers/react/tests/v0_9/adapter.test.tsx @@ -14,22 +14,23 @@ * limitations under the License. */ -import { describe, it, expect, vi } from 'vitest'; -import { render, screen, act } from '@testing-library/react'; -import { createReactComponent } from '../../src/v0_9/adapter'; -import { A2uiSurface } from '../../src/v0_9/A2uiSurface'; -import { ComponentContext, ComponentModel, SurfaceModel, Catalog, CommonSchemas } from '@a2ui/web_core/v0_9'; -import { z } from 'zod'; +import {describe, it, expect, vi} from 'vitest'; +import {render, screen, act} from '@testing-library/react'; +import {createReactComponent} from '../../src/v0_9/adapter'; +import {A2uiSurface} from '../../src/v0_9/A2uiSurface'; +import {reactSignal} from '../../src/v0_9/reactSignal'; +import {ComponentContext, ComponentModel, SurfaceModel, Catalog, CommonSchemas} from '@a2ui/web_core/v0_9'; +import {z} from 'zod'; const mockCatalog = new Catalog('test', [], []); describe('adapter', () => { it('should render component with resolved props', () => { - const surface = new SurfaceModel('test-surface', mockCatalog); - const compModel = new ComponentModel('c1', 'TestComp', { text: 'Hello World', child: 'child1' }); + const surface = new SurfaceModel('test-surface', mockCatalog, reactSignal); + const compModel = new ComponentModel('c1', 'TestComp', {text: 'Hello World', child: 'child1'}); surface.componentsModel.addComponent(compModel); - const context = new ComponentContext(surface, 'c1', '/'); + const context = new ComponentContext(surface, 'c1', reactSignal, '/'); const TestApiDef = { name: 'TestComp', @@ -41,7 +42,7 @@ describe('adapter', () => { const TestComponent = createReactComponent( TestApiDef, - ({ props, buildChild }) => { + ({props, buildChild}) => { return
{props.text} {props.child && buildChild(props.child)} @@ -58,14 +59,14 @@ describe('adapter', () => { }); it('should react to data model changes', async () => { - const surface = new SurfaceModel('test-surface', mockCatalog); - const compModel = new ComponentModel('c1', 'TestComp', { text: { path: '/greeting' } }); + const surface = new SurfaceModel('test-surface', mockCatalog, reactSignal); + const compModel = new ComponentModel('c1', 'TestComp', {text: {path: '/greeting'}}); surface.componentsModel.addComponent(compModel); - + // Set initial data surface.dataModel.set('/greeting', 'Hello Reactive'); - const context = new ComponentContext(surface, 'c1', '/'); + const context = new ComponentContext(surface, 'c1', reactSignal, '/'); const TestApiDef = { name: 'TestComp', @@ -76,12 +77,12 @@ describe('adapter', () => { const TestComponent = createReactComponent( TestApiDef, - ({ props }) => { + ({props}) => { return
{props.text}
; } ); - const { getByTestId } = render( null} />); + const {getByTestId} = render( null} />); expect(getByTestId('msg').textContent).toBe('Hello Reactive'); @@ -94,11 +95,13 @@ describe('adapter', () => { }); it('should clean up listeners on unmount', () => { - const surface = new SurfaceModel('test-surface', mockCatalog); - const compModel = new ComponentModel('c1', 'TestComp', { text: { path: '/greeting' } }); + // @ts-ignore + const surface = new SurfaceModel('test-surface', mockCatalog, reactSignal); + const compModel = new ComponentModel('c1', 'TestComp', {text: {path: '/greeting'}}); surface.componentsModel.addComponent(compModel); - - const context = new ComponentContext(surface, 'c1', '/'); + + // @ts-ignore + const context = new ComponentContext(surface, 'c1', reactSignal, '/'); const unsubscribeSpy = vi.fn(); const spyAddListener = vi.spyOn(context.dataContext, 'subscribeDynamicValue').mockReturnValue({ @@ -115,58 +118,59 @@ describe('adapter', () => { const TestComponent = createReactComponent( TestApiDef, - ({ props }) => { + ({props}) => { return
{props.text}
; } ); - const { unmount } = render( null} />); + const {unmount} = render( null} />); expect(spyAddListener).toHaveBeenCalled(); - + unmount(); - + expect(unsubscribeSpy).toHaveBeenCalled(); }); it('preserves progressive rendering (avoids stale closures from over-memoization)', async () => { - const ParentApiDef = { name: 'TestParent', schema: z.object({ child: CommonSchemas.ComponentId }) }; - const ChildApiDef = { name: 'TestChild', schema: z.object({ text: CommonSchemas.DynamicString }) }; - + const ParentApiDef = {name: 'TestParent', schema: z.object({child: CommonSchemas.ComponentId})}; + const ChildApiDef = {name: 'TestChild', schema: z.object({text: CommonSchemas.DynamicString})}; + let parentRenderCount = 0; - const TestParent = createReactComponent(ParentApiDef, ({ props, buildChild }) => { + const TestParent = createReactComponent(ParentApiDef, ({props, buildChild}) => { parentRenderCount++; return
{props.child && buildChild(props.child)}
; }); - const TestChild = createReactComponent(ChildApiDef, ({ props }) => ( + const TestChild = createReactComponent(ChildApiDef, ({props}) => ( {props.text} )); const testCatalog = new Catalog('test', [TestParent, TestChild], []); - const surface = new SurfaceModel('test-surface', testCatalog); - + // @ts-ignore + const surface = new SurfaceModel('test-surface', testCatalog, undefined, reactSignal); + // 1. Initial State: Parent component exists, but its child is missing from the surface. - const parentModel = new ComponentModel('root', 'TestParent', { child: 'child1' }); + const parentModel = new ComponentModel('root', 'TestParent', {child: 'child1'}); surface.componentsModel.addComponent(parentModel); - const { getByTestId, queryByTestId } = render(); + const {getByTestId, queryByTestId} = render(); // Assert the missing child renders the fallback expect(getByTestId('parent').textContent).toContain('[Loading child1...]'); - + const countBeforeChild = parentRenderCount; // 2. Simulate streaming 'updateComponents' adding the missing child await act(async () => { - surface.componentsModel.addComponent(new ComponentModel('child1', 'TestChild', { text: 'Loaded Data' })); + surface.componentsModel.addComponent(new ComponentModel('child1', 'TestChild', {text: 'Loaded Data'})); }); // 3. Child should automatically resolve through DeferredChild's subscription expect(queryByTestId('resolved')).not.toBeNull(); expect(getByTestId('resolved').textContent).toBe('Loaded Data'); - + // Crucially, the parent should NOT have re-rendered because of the child addition. // The DeferredChild wrapper localized the update. expect(parentRenderCount).toBe(countBeforeChild); diff --git a/renderers/react/tests/v0_9/components.test.tsx b/renderers/react/tests/v0_9/components.test.tsx index 58150876c..19197a51a 100644 --- a/renderers/react/tests/v0_9/components.test.tsx +++ b/renderers/react/tests/v0_9/components.test.tsx @@ -14,37 +14,38 @@ * limitations under the License. */ -import { describe, it, expect, vi } from 'vitest'; -import { render, screen, fireEvent } from '@testing-library/react'; -import { ComponentContext, ComponentModel, SurfaceModel, Catalog } from '@a2ui/web_core/v0_9'; +import {describe, it, expect, vi} from 'vitest'; +import {render, screen, fireEvent} from '@testing-library/react'; +import {ComponentContext, ComponentModel, SurfaceModel, Catalog} from '@a2ui/web_core/v0_9'; -import { Text } from '../../src/v0_9/catalog/minimal/components/Text'; -import { Button } from '../../src/v0_9/catalog/minimal/components/Button'; -import { Row } from '../../src/v0_9/catalog/minimal/components/Row'; -import { Column } from '../../src/v0_9/catalog/minimal/components/Column'; -import { TextField } from '../../src/v0_9/catalog/minimal/components/TextField'; +import {Text} from '../../src/v0_9/catalog/minimal/components/Text'; +import {Button} from '../../src/v0_9/catalog/minimal/components/Button'; +import {Row} from '../../src/v0_9/catalog/minimal/components/Row'; +import {Column} from '../../src/v0_9/catalog/minimal/components/Column'; +import {TextField} from '../../src/v0_9/catalog/minimal/components/TextField'; +import {reactSignal} from '../../src/v0_9/reactSignal'; const mockCatalog = new Catalog('test', [], []); function createContext(type: string, properties: any) { - const surface = new SurfaceModel('test-surface', mockCatalog); + const surface = new SurfaceModel('test-surface', mockCatalog, reactSignal); const compModel = new ComponentModel('test-id', type, properties); surface.componentsModel.addComponent(compModel); - return new ComponentContext(surface, 'test-id', '/'); + return new ComponentContext(surface, 'test-id', reactSignal, '/'); } describe('Text', () => { it('renders text and variant correctly', () => { - const ctx = createContext('Text', { text: 'Hello', variant: 'h1' }); - const { container } = render( null} />); + const ctx = createContext('Text', {text: 'Hello', variant: 'h1'}); + const {container} = render( null} />); const h1 = container.querySelector('h1'); expect(h1).not.toBeNull(); expect(h1?.textContent).toBe('Hello'); }); it('renders default variant', () => { - const ctx = createContext('Text', { text: 'Hello' }); - const { container } = render( null} />); + const ctx = createContext('Text', {text: 'Hello'}); + const {container} = render( null} />); const span = container.querySelector('span'); expect(span).not.toBeNull(); expect(span?.textContent).toBe('Hello'); @@ -53,10 +54,10 @@ describe('Text', () => { describe('Button', () => { it('renders and dispatches action', () => { - const ctx = createContext('Button', { + const ctx = createContext('Button', { child: 'btn-child', variant: 'primary', - action: { event: { name: 'test_action' } } + action: {event: {name: 'test_action'}} }); const spy = vi.spyOn(ctx, 'dispatchAction').mockResolvedValue(); @@ -68,12 +69,12 @@ describe('Button', () => { const button = screen.getByRole('button'); expect(button).not.toBeNull(); expect(screen.getByTestId('child').textContent).toBe('btn-child'); - + // Check style for primary variant expect(button.style.backgroundColor).toBe('rgb(0, 123, 255)'); // #007bff in rgb fireEvent.click(button); - expect(spy).toHaveBeenCalledWith({ event: { name: 'test_action' } }); + expect(spy).toHaveBeenCalledWith({event: {name: 'test_action'}}); }); }); @@ -87,7 +88,7 @@ describe('Row', () => { const buildChild = vi.fn().mockImplementation((id) =>
{id}
); - const { container } = render(); + const {container} = render(); const rowDiv = container.firstChild as HTMLElement; expect(rowDiv.style.display).toBe('flex'); expect(rowDiv.style.flexDirection).toBe('row'); @@ -109,7 +110,7 @@ describe('Column', () => { const buildChild = vi.fn().mockImplementation((id) =>
{id}
); - const { container } = render(); + const {container} = render(); const colDiv = container.firstChild as HTMLElement; expect(colDiv.style.display).toBe('flex'); expect(colDiv.style.flexDirection).toBe('column'); @@ -128,7 +129,7 @@ describe('TextField', () => { variant: 'shortText' }); - const { container } = render( null} />); + const {container} = render( null} />); const label = container.querySelector('label'); expect(label?.textContent).toBe('Username'); @@ -144,7 +145,7 @@ describe('TextField', () => { variant: 'longText' }); - const { container } = render( null} />); + const {container} = render( null} />); const textarea = container.querySelector('textarea'); expect(textarea).not.toBeNull(); expect(textarea?.value).toBe('lots of text'); @@ -153,16 +154,16 @@ describe('TextField', () => { it('updates data model on change', () => { const ctx = createContext('TextField', { label: 'Username', - value: { path: '/user' } + value: {path: '/user'} }); const spySet = vi.spyOn(ctx.dataContext, 'set'); - const { container } = render( null} />); + const {container} = render( null} />); const input = container.querySelector('input'); - - fireEvent.change(input!, { target: { value: 'bob' } }); - + + fireEvent.change(input!, {target: {value: 'bob'}}); + expect(spySet).toHaveBeenCalledWith('/user', 'bob'); }); }); diff --git a/renderers/web_core/package-lock.json b/renderers/web_core/package-lock.json index 0dd6ddc9e..42bfc4a5f 100644 --- a/renderers/web_core/package-lock.json +++ b/renderers/web_core/package-lock.json @@ -26,8 +26,8 @@ } }, "node_modules/@angular/core": { - "version": "21.2.6", - "integrity": "sha512-svgK5DhFlQlS+sMybXftn08rHHRiDGY/uIKT5LZUaKgyffnkPb8uClpMIW0NzANtU8qs8pwgDZFoJw85Ia3oqQ==", + "version": "21.2.7", + "integrity": "sha512-4bnskeRNNOZMn3buVw47Zz9Py4B8AZgYHe5xBEMOY5/yrldb7OFje5gWCWls23P18FKwhl+Xx1hgnOEPSs29gw==", "dev": true, "license": "MIT", "dependencies": { @@ -37,7 +37,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.6", + "@angular/compiler": "21.2.7", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -130,8 +130,8 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -205,8 +205,8 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -399,8 +399,8 @@ } }, "node_modules/@preact/signals-core": { - "version": "1.14.0", - "integrity": "sha512-AowtCcCU/33lFlh1zRFf/u+12rfrhtNakj7UpaGEsmMwUKpKWMVvcktOGcwBBNiB4lWrZWc01LhiyyzVklJyaQ==", + "version": "1.14.1", + "integrity": "sha512-vxPpfXqrwUe9lpjqfYNjAF/0RF/eFGeLgdJzdmIIZjpOnTmGmAB4BjWone562mJGMRP4frU6iZ6ei3PDsu52Ng==", "license": "MIT", "funding": { "type": "opencollective", @@ -447,19 +447,19 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.2", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", + "version": "8.58.0", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/type-utils": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -469,21 +469,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.2", + "@typescript-eslint/parser": "^8.58.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.57.2", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", + "version": "8.58.0", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3" }, "engines": { @@ -495,17 +495,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.2", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", + "version": "8.58.0", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.2", - "@typescript-eslint/types": "^8.57.2", + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "engines": { @@ -516,17 +516,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.2", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", + "version": "8.58.0", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -537,8 +537,8 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.2", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "version": "8.58.0", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, "license": "MIT", "engines": { @@ -549,20 +549,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.2", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", + "version": "8.58.0", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -573,12 +573,12 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.57.2", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", + "version": "8.58.0", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", "dev": true, "license": "MIT", "engines": { @@ -590,20 +590,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.2", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", + "version": "8.58.0", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -613,19 +613,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "version": "8.58.0", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -636,16 +636,16 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "version": "8.58.0", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -766,6 +766,18 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", @@ -782,12 +794,12 @@ } }, "node_modules/balanced-match": { - "version": "3.0.1", - "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "version": "4.0.4", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 16" + "node": "18 || 20 || >=22" } }, "node_modules/base64-js": { @@ -832,15 +844,15 @@ } }, "node_modules/brace-expansion": { - "version": "4.0.1", - "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", + "version": "5.0.5", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^3.0.0" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">= 18" + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -975,6 +987,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", @@ -1400,8 +1424,8 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1421,18 +1445,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/eslint/node_modules/ignore": { "version": "5.3.2", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", @@ -1548,6 +1560,12 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/extend": { "version": "3.0.2", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", @@ -1596,6 +1614,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", @@ -1617,6 +1647,23 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.5.0", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/figures": { "version": "3.2.0", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", @@ -1716,18 +1763,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fsevents": { "version": "2.3.3", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", @@ -1832,15 +1867,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { @@ -2398,8 +2433,8 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, @@ -2523,6 +2558,18 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", @@ -2542,12 +2589,12 @@ } }, "node_modules/minimatch": { - "version": "10.2.4", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -2556,27 +2603,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimatch/node_modules/balanced-match": { - "version": "4.0.4", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.5", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/minimist-options": { "version": "4.1.0", "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", @@ -2849,12 +2875,12 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.4", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -2907,6 +2933,12 @@ "signal-exit": "^3.0.2" } }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/punycode": { "version": "2.3.1", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", @@ -3086,6 +3118,18 @@ "node": ">=8.10.0" } }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/redent": { "version": "3.0.0", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", @@ -3159,6 +3203,12 @@ "node": ">=8" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/retry": { "version": "0.12.0", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", @@ -3279,10 +3329,16 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "version": "4.1.0", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/spdx-correct": { "version": "3.2.0", @@ -3463,35 +3519,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tmp": { "version": "0.0.33", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", @@ -3565,18 +3592,6 @@ "typescript": ">=4.0.0" } }, - "node_modules/ts-declaration-location/node_modules/picomatch": { - "version": "4.0.4", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tslib": { "version": "2.8.1", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", @@ -3621,15 +3636,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.57.2", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", + "version": "8.58.0", + "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2" + "@typescript-eslint/eslint-plugin": "8.58.0", + "@typescript-eslint/parser": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3640,7 +3655,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/undici-types": { @@ -3749,6 +3764,27 @@ "node": ">=18.0.0" } }, + "node_modules/wireit/node_modules/balanced-match": { + "version": "3.0.1", + "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/wireit/node_modules/brace-expansion": { + "version": "4.0.1", + "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^3.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", @@ -3788,18 +3824,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "4.1.0", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/y18n": { "version": "5.0.8", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", @@ -3863,12 +3887,12 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "version": "3.25.2", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", "license": "ISC", "peerDependencies": { - "zod": "^3.25 || ^4" + "zod": "^3.25.28 || ^4" } } } -} \ No newline at end of file +} diff --git a/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.test.ts b/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.test.ts index 925f692cf..56e2e4bc7 100644 --- a/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.test.ts +++ b/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.test.ts @@ -23,15 +23,24 @@ import {DataModel} from '../../state/data-model.js'; import {DataContext} from '../../rendering/data-context.js'; import {A2uiExpressionError} from '../../errors.js'; import {Catalog, ComponentApi} from '../../catalog/types.js'; - -const testCatalog = new Catalog('test', [], BASIC_FUNCTIONS); - -function invoke(name: string, args: Record, context: DataContext) { +import {testFrameworkSignal} from '../../test/test_signals.js'; + +const testCatalog = new Catalog( + 'test', + [], + BASIC_FUNCTIONS, +); + +function invoke( + name: string, + args: Record, + context: DataContext<'preact'>, +) { return testCatalog.invoker(name, args, context); } const createTestDataContext = ( - model: DataModel, + model: DataModel<'preact'>, path: string, functionInvoker: any = testCatalog.invoker, ) => { @@ -40,11 +49,11 @@ const createTestDataContext = ( catalog: {invoker: functionInvoker}, dispatchError: () => {}, } as any; - return new DataContext(mockSurface, path); + return new DataContext(mockSurface, testFrameworkSignal, path); }; describe('BASIC_FUNCTIONS', () => { - const dataModel = new DataModel({a: 10, b: 20}); + const dataModel = new DataModel(testFrameworkSignal, {a: 10, b: 20}); const context = createTestDataContext(dataModel, '/'); describe('Arithmetic', () => { diff --git a/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.ts b/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.ts index 4f04c819f..a79786a32 100644 --- a/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.ts +++ b/renderers/web_core/src/v0_9/basic_catalog/functions/basic_functions.ts @@ -285,7 +285,7 @@ export const OpenUrlImplementation = createFunctionImplementation( * Standard function implementations for the Basic Catalog. * These functions cover arithmetic, comparison, logic, string manipulation, validation, and formatting. */ -export const BASIC_FUNCTIONS: FunctionImplementation[] = [ +export const BASIC_FUNCTIONS: FunctionImplementation[] = [ AddImplementation, SubtractImplementation, MultiplyImplementation, diff --git a/renderers/web_core/src/v0_9/catalog/function_invoker.ts b/renderers/web_core/src/v0_9/catalog/function_invoker.ts index 3d5eef5c5..f069a1b57 100644 --- a/renderers/web_core/src/v0_9/catalog/function_invoker.ts +++ b/renderers/web_core/src/v0_9/catalog/function_invoker.ts @@ -15,6 +15,7 @@ */ import {DataContext} from '../rendering/data-context.js'; +import {SignalKinds} from '../reactivity/signals.js'; /** * A function that invokes a catalog function by name and returns its result synchronously or as a Signal. @@ -25,9 +26,9 @@ import {DataContext} from '../rendering/data-context.js'; * @param abortSignal An optional AbortSignal for asynchronous or long-running operations. * @returns The result of the function call, which can be a literal, a Signal, or a Promise (handled by the caller). */ -export type FunctionInvoker = ( +export type FunctionInvoker> = ( name: string, args: Record, - context: DataContext, + context: DataContext, abortSignal?: AbortSignal, ) => any; diff --git a/renderers/web_core/src/v0_9/catalog/types.test.ts b/renderers/web_core/src/v0_9/catalog/types.test.ts index 1b6041f3c..537b0fbf8 100644 --- a/renderers/web_core/src/v0_9/catalog/types.test.ts +++ b/renderers/web_core/src/v0_9/catalog/types.test.ts @@ -103,11 +103,12 @@ describe('InferredComponentApiSchemaType', () => { field2: z.number().optional(), }); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const mockApi = { name: 'MockComp', schema: mockSchema, } satisfies ComponentApi; - // Appease typescript-eslint/no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars type _ = typeof mockApi; // Type-level equivalence assertion using z.infer @@ -119,6 +120,7 @@ describe('InferredComponentApiSchemaType', () => { // inferredIsAny only accepts "true" if `InferredType` is "any". // This happens when `mockApi: ComponentApi`, but doesn't when // `mockApi {} satisfies ComponentApi`! + // eslint-disable-next-line @typescript-eslint/no-unused-vars const inferredIsAny: IsAny = false; // When types are not "any", check that they're the same by checking if they @@ -130,6 +132,7 @@ describe('InferredComponentApiSchemaType', () => { : false; // typesMatchExact only accepts "true" if `TypesAreEquivalent` + // eslint-disable-next-line @typescript-eslint/no-unused-vars const typesMatchExact: TypesAreEquivalent = true; }); diff --git a/renderers/web_core/src/v0_9/catalog/types.ts b/renderers/web_core/src/v0_9/catalog/types.ts index c4d6a6abf..ba3e8f375 100644 --- a/renderers/web_core/src/v0_9/catalog/types.ts +++ b/renderers/web_core/src/v0_9/catalog/types.ts @@ -15,9 +15,10 @@ */ import {z} from 'zod'; -import {DataContext} from '../rendering/data-context.js'; import {Signal} from '@preact/signals-core'; +import {DataContext} from '../rendering/data-context.js'; import {A2uiExpressionError} from '../errors.js'; +import {SignalKinds} from '../reactivity/signals.js'; /** * Robust check for a Preact Signal that works across package boundaries. @@ -61,10 +62,12 @@ export interface FunctionApi { /** * A function implementation that can be registered with the evaluator or basic catalog. */ -export interface FunctionImplementation extends FunctionApi { +export interface FunctionImplementation< + SK extends keyof SignalKinds, +> extends FunctionApi { execute( args: Record, - context: DataContext, + context: DataContext, abortSignal?: AbortSignal, ): unknown | Signal; } @@ -72,21 +75,22 @@ export interface FunctionImplementation extends FunctionApi { export function createFunctionImplementation< Schema extends z.ZodTypeAny, TReturn extends A2uiReturnType, + SK extends keyof SignalKinds, >( api: {name: string; returnType: TReturn; schema: Schema}, execute: ( args: z.infer, - context: DataContext, + context: DataContext, abortSignal?: AbortSignal, ) => InferA2uiReturnType | Signal>, -): FunctionImplementation { +): FunctionImplementation { return { name: api.name, returnType: api.returnType, schema: api.schema, execute: execute as ( args: Record, - ctx: DataContext, + ctx: DataContext, ab?: AbortSignal, ) => unknown, }; @@ -127,7 +131,10 @@ export type InferredComponentApiSchemaType = z.infer< /** * A collection of available components and functions. */ -export class Catalog { +export class Catalog< + T extends ComponentApi, + SK extends keyof SignalKinds, +> { readonly id: string; /** @@ -139,7 +146,7 @@ export class Catalog { /** * Map of functions provided by this catalog. */ - readonly functions: ReadonlyMap; + readonly functions: ReadonlyMap>; /** * The schema for theme parameters used by this catalog. @@ -150,12 +157,12 @@ export class Catalog { * A ready-to-use FunctionInvoker callback that delegates to this catalog's functions. * Can be passed directly to a DataContext. */ - readonly invoker: FunctionInvoker; + readonly invoker: FunctionInvoker; constructor( id: string, components: T[], - functions: FunctionImplementation[] = [], + functions: FunctionImplementation[] = [], themeSchema?: z.ZodObject, ) { this.id = id; @@ -166,7 +173,7 @@ export class Catalog { } this.components = compMap; - const funcMap = new Map(); + const funcMap = new Map>(); for (const fn of functions) { funcMap.set(fn.name, fn); } diff --git a/renderers/web_core/src/v0_9/index.ts b/renderers/web_core/src/v0_9/index.ts index 51be3ccbb..7e763bb80 100644 --- a/renderers/web_core/src/v0_9/index.ts +++ b/renderers/web_core/src/v0_9/index.ts @@ -24,6 +24,7 @@ export * from './catalog/function_invoker.js'; export * from './catalog/types.js'; export * from './common/events.js'; +export * from './reactivity/signals.js'; export * from './processing/message-processor.js'; export * from './rendering/component-context.js'; export * from './rendering/data-context.js'; diff --git a/renderers/web_core/src/v0_9/processing/message-processor.test.ts b/renderers/web_core/src/v0_9/processing/message-processor.test.ts index 9217f5313..4d2de9b77 100644 --- a/renderers/web_core/src/v0_9/processing/message-processor.test.ts +++ b/renderers/web_core/src/v0_9/processing/message-processor.test.ts @@ -19,18 +19,23 @@ import {describe, it, beforeEach} from 'node:test'; import {MessageProcessor} from './message-processor.js'; import {Catalog, ComponentApi} from '../catalog/types.js'; import {z} from 'zod'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('MessageProcessor', () => { - let processor: MessageProcessor; - let testCatalog: Catalog; + let processor: MessageProcessor; + let testCatalog: Catalog; let actions: any[] = []; beforeEach(() => { actions = []; testCatalog = new Catalog('test-catalog', []); - processor = new MessageProcessor([testCatalog], async a => { - actions.push(a); - }); + processor = new MessageProcessor( + [testCatalog], + testFrameworkSignal, + async a => { + actions.push(a); + }, + ); }); describe('getClientCapabilities', () => { @@ -52,7 +57,7 @@ describe('MessageProcessor', () => { }), }; const cat = new Catalog('cat-1', [buttonApi]); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const inlineCat = caps['v0.9'].inlineCatalogs![0]; @@ -89,7 +94,7 @@ describe('MessageProcessor', () => { }), }; const cat = new Catalog('cat-ref', [customApi]); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const titleSchema = @@ -129,7 +134,7 @@ describe('MessageProcessor', () => { }); const cat = new Catalog('cat-full', [buttonApi], [addFn], themeSchema); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const inlineCat = caps['v0.9'].inlineCatalogs![0]; @@ -163,7 +168,7 @@ describe('MessageProcessor', () => { it('omits functions and theme when catalog has none', () => { const compApi: ComponentApi = {name: 'EmptyComp', schema: z.object({})}; const cat = new Catalog('cat-empty', [compApi]); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const inlineCat = caps['v0.9'].inlineCatalogs![0]; @@ -188,7 +193,7 @@ describe('MessageProcessor', () => { }), }; const cat = new Catalog('cat-deep', [deepApi]); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const properties = @@ -212,7 +217,7 @@ describe('MessageProcessor', () => { }), }; const cat = new Catalog('cat-edge', [edgeApi]); - const proc = new MessageProcessor([cat]); + const proc = new MessageProcessor([cat], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); const properties = @@ -245,7 +250,7 @@ describe('MessageProcessor', () => { const themeSchema = z.object({color: z.string()}); const cat2 = new Catalog('cat-2', [], [addFn], themeSchema); - const proc = new MessageProcessor([cat1, cat2]); + const proc = new MessageProcessor([cat1, cat2], testFrameworkSignal); const caps = proc.getClientCapabilities({includeInlineCatalogs: true}); assert.strictEqual(caps['v0.9'].inlineCatalogs!.length, 2); diff --git a/renderers/web_core/src/v0_9/processing/message-processor.ts b/renderers/web_core/src/v0_9/processing/message-processor.ts index 75c61a5a7..e5edc8c9a 100644 --- a/renderers/web_core/src/v0_9/processing/message-processor.ts +++ b/renderers/web_core/src/v0_9/processing/message-processor.ts @@ -19,6 +19,7 @@ import {Catalog, ComponentApi} from '../catalog/types.js'; import {SurfaceGroupModel} from '../state/surface-group-model.js'; import {ComponentModel} from '../state/component-model.js'; import {Subscription} from '../common/events.js'; +import {FrameworkSignal, SignalKinds} from '../reactivity/signals.js'; import {zodToJsonSchema} from 'zod-to-json-schema'; import { @@ -47,8 +48,11 @@ export interface CapabilitiesOptions { * The central processor for A2UI messages. * @template T The concrete type of the ComponentApi. */ -export class MessageProcessor { - readonly model: SurfaceGroupModel; +export class MessageProcessor< + T extends ComponentApi, + SK extends keyof SignalKinds, +> { + readonly model: SurfaceGroupModel; /** * Creates a new message processor. @@ -57,10 +61,11 @@ export class MessageProcessor { * @param actionHandler A global handler for actions from all surfaces. */ constructor( - private catalogs: Catalog[], + private catalogs: Catalog[], + private readonly frameworkSignal: FrameworkSignal, private actionHandler?: ActionListener, ) { - this.model = new SurfaceGroupModel(); + this.model = new SurfaceGroupModel(); if (this.actionHandler) { this.model.onAction.subscribe(this.actionHandler); } @@ -88,7 +93,7 @@ export class MessageProcessor { return capabilities; } - private generateInlineCatalog(catalog: Catalog): InlineCatalog { + private generateInlineCatalog(catalog: Catalog): InlineCatalog { const components: Record = {}; for (const [name, api] of catalog.components.entries()) { @@ -210,7 +215,9 @@ export class MessageProcessor { /** * Subscribes to surface creation events. */ - onSurfaceCreated(handler: (surface: SurfaceModel) => void): Subscription { + onSurfaceCreated( + handler: (surface: SurfaceModel) => void, + ): Subscription { return this.model.onSurfaceCreated.subscribe(handler); } @@ -281,9 +288,10 @@ export class MessageProcessor { throw new A2uiStateError(`Surface ${surfaceId} already exists.`); } - const surface = new SurfaceModel( + const surface = new SurfaceModel( surfaceId, catalog, + this.frameworkSignal, theme, sendDataModel ?? false, ); diff --git a/renderers/web_core/src/v0_9/rendering/component-context.test.ts b/renderers/web_core/src/v0_9/rendering/component-context.test.ts index 8dfedd53e..899496bee 100644 --- a/renderers/web_core/src/v0_9/rendering/component-context.test.ts +++ b/renderers/web_core/src/v0_9/rendering/component-context.test.ts @@ -19,9 +19,14 @@ import * as assert from 'node:assert'; import {ComponentContext} from './component-context.js'; import {SurfaceModel} from '../state/surface-model.js'; import {ComponentModel} from '../state/component-model.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('ComponentContext', () => { - const mockSurface = new SurfaceModel('surface1', {} as any); + const mockSurface = new SurfaceModel( + 'surface1', + {} as any, + testFrameworkSignal, + ); const componentId = 'comp1'; // Add a component to the surface model for testing @@ -29,14 +34,22 @@ describe('ComponentContext', () => { mockSurface.componentsModel.addComponent(componentModel); it('initializes correctly', () => { - const context = new ComponentContext(mockSurface, componentId); + const context = new ComponentContext( + mockSurface, + componentId, + testFrameworkSignal, + ); assert.strictEqual(context.componentModel, componentModel); assert.ok(context.dataContext); assert.strictEqual(context.surfaceComponents, mockSurface.componentsModel); }); it('dispatches actions', async () => { - const context = new ComponentContext(mockSurface, componentId); + const context = new ComponentContext( + mockSurface, + componentId, + testFrameworkSignal, + ); let actionDispatched: any = null; const subscription = mockSurface.onAction.subscribe((action: any) => { @@ -53,12 +66,17 @@ describe('ComponentContext', () => { it('throws error if component not found', () => { assert.throws(() => { - new ComponentContext(mockSurface, 'nonExistentId'); + new ComponentContext(mockSurface, 'nonExistentId', testFrameworkSignal); }, /Component not found: nonExistentId/); }); it('creates data context with correct base path', () => { - const context = new ComponentContext(mockSurface, componentId, '/foo/bar'); + const context = new ComponentContext( + mockSurface, + componentId, + testFrameworkSignal, + '/foo/bar', + ); assert.strictEqual(context.dataContext.path, '/foo/bar'); }); }); diff --git a/renderers/web_core/src/v0_9/rendering/component-context.ts b/renderers/web_core/src/v0_9/rendering/component-context.ts index 910ee2345..92225f143 100644 --- a/renderers/web_core/src/v0_9/rendering/component-context.ts +++ b/renderers/web_core/src/v0_9/rendering/component-context.ts @@ -19,19 +19,20 @@ import {ComponentModel} from '../state/component-model.js'; import type {SurfaceModel} from '../state/surface-model.js'; import type {SurfaceComponentsModel} from '../state/surface-components-model.js'; import {A2uiStateError} from '../errors.js'; +import {FrameworkSignal, SignalKinds} from '../reactivity/signals.js'; /** * Context provided to components during rendering. * It provides access to the component's model, the data context, and a way to dispatch actions. */ -export class ComponentContext { +export class ComponentContext> { /** The state model for this specific component, providing access to its properties and state. */ readonly componentModel: ComponentModel; /** * The data context scoped to this component's position in the visual hierarchy. * Uses the `dataModelBasePath` to resolve relative data paths. */ - readonly dataContext: DataContext; + readonly dataContext: DataContext; /** The collection of all component models for the current surface, allowing lookups by ID. */ readonly surfaceComponents: SurfaceComponentsModel; @@ -43,8 +44,9 @@ export class ComponentContext { * @param dataModelBasePath The base path for data model access (default: '/'). */ constructor( - surface: SurfaceModel, + surface: SurfaceModel, componentId: string, + frameworkSignal: FrameworkSignal, dataModelBasePath: string = '/', ) { const model = surface.componentsModel.get(componentId); @@ -54,7 +56,11 @@ export class ComponentContext { this.componentModel = model; this.surfaceComponents = surface.componentsModel; - this.dataContext = new DataContext(surface, dataModelBasePath); + this.dataContext = new DataContext( + surface, + frameworkSignal, + dataModelBasePath, + ); this._actionDispatcher = action => surface.dispatchAction(action, this.componentModel.id); } diff --git a/renderers/web_core/src/v0_9/rendering/data-context.test.ts b/renderers/web_core/src/v0_9/rendering/data-context.test.ts index 3dac94ae2..506026b46 100644 --- a/renderers/web_core/src/v0_9/rendering/data-context.test.ts +++ b/renderers/web_core/src/v0_9/rendering/data-context.test.ts @@ -21,9 +21,10 @@ import {z} from 'zod'; import {DataModel} from '../state/data-model.js'; import {DataContext} from './data-context.js'; import {A2uiExpressionError} from '../errors.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; const createTestDataContext = ( - model: DataModel, + model: DataModel<'preact'>, path: string, functionInvoker: any = () => null, dispatchError: (err: any) => void = () => {}, @@ -33,15 +34,15 @@ const createTestDataContext = ( catalog: {invoker: functionInvoker}, dispatchError, } as any; - return new DataContext(mockSurface, path); + return new DataContext(mockSurface, testFrameworkSignal, path); }; describe('DataContext', () => { - let model: DataModel; - let context: DataContext; + let model: DataModel<'preact'>; + let context: DataContext<'preact'>; beforeEach(() => { - model = new DataModel({ + model = new DataModel(testFrameworkSignal, { user: { name: 'Alice', address: { diff --git a/renderers/web_core/src/v0_9/rendering/data-context.ts b/renderers/web_core/src/v0_9/rendering/data-context.ts index 76ff4b789..1fb016752 100644 --- a/renderers/web_core/src/v0_9/rendering/data-context.ts +++ b/renderers/web_core/src/v0_9/rendering/data-context.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import {signal, computed, Signal, effect} from '@preact/signals-core'; import {z} from 'zod'; import {DataModel, DataSubscription} from '../state/data-model.js'; import type { @@ -25,9 +24,9 @@ import type { } from '../schema/common-types.js'; import {A2uiExpressionError} from '../errors.js'; import {isSignal} from '../catalog/types.js'; - import {FunctionInvoker} from '../catalog/function_invoker.js'; import {SurfaceModel} from '../state/surface-model.js'; +import {FrameworkSignal, SignalKinds} from '../reactivity/signals.js'; /** * A contextual view of the main DataModel, serving as the unified interface for resolving @@ -37,20 +36,24 @@ import {SurfaceModel} from '../state/surface-model.js'; * It automatically handles resolving relative paths against the component's current scope * and provides tools for evaluating complex, reactive expressions. */ -export class DataContext { +export class DataContext> { /** The shared, global DataModel instance for the entire UI surface. */ - readonly dataModel: DataModel; + readonly dataModel: DataModel; /** A callback for executing function calls defined in the A2UI component tree. */ - readonly functionInvoker: FunctionInvoker; + readonly functionInvoker: FunctionInvoker; + + private readonly signalCleanups = new WeakMap void>(); /** * Initializes a new DataContext. * * @param surface The surface model this context belongs to. + * @param frameworkSignal The framework signal implementation to use for reactive values. * @param path The absolute path in the DataModel that this context is scoped to (its "current working directory"). */ constructor( - readonly surface: SurfaceModel, + readonly surface: SurfaceModel, + readonly frameworkSignal: FrameworkSignal, readonly path: string, ) { this.dataModel = surface.dataModel; @@ -140,10 +143,10 @@ export class DataContext { const sig = this.resolveSignal(value); let isSync = true; - let currentValue = sig.peek(); + let currentValue = this.frameworkSignal.unwrap(sig); - const dispose = effect(() => { - const val = sig.value; + const destroy = this.frameworkSignal.effect(() => { + const val = this.frameworkSignal.unwrap(sig); currentValue = val; if (!isSync) { onChange(val); @@ -156,40 +159,39 @@ export class DataContext { return currentValue; }, unsubscribe: () => { - dispose(); - if ((sig as any).unsubscribe) { - (sig as any).unsubscribe(); - } + destroy(); + const cleanup = this.signalCleanups.get(sig); + if (cleanup) cleanup(); }, }; } /** - * Returns a Preact Signal representing the reactive dynamic value. + * Returns a Signal representing the reactive dynamic value. * * This method recursively resolves any nested path bindings or function calls into a * single, reactive `Signal`. Any changes to the underlying data or function dependencies * will cause this signal's value to update. * * @param value The DynamicValue to evaluate and observe. - * @returns A Preact Signal containing the reactive result of the evaluation. + * @returns A signal containing the reactive result of the evaluation. */ - resolveSignal(value: DynamicValue): Signal { + resolveSignal(value: DynamicValue): SignalKinds[SK] { // 1. Literal if (typeof value !== 'object' || value === null || Array.isArray(value)) { - return signal(value as V); + return this.frameworkSignal.wrap(value as V); } // 2. Path Check if ('path' in value) { - const absolutePath = this.resolvePath((value as DataBinding).path); - return this.dataModel.getSignal(absolutePath) as Signal; + const absolutePath = this.resolvePath(value.path); + return this.dataModel.getSignal(absolutePath); } // 3. Function Call if ('call' in value) { const call = value as FunctionCall; - const argSignals: Record> = {}; + const argSignals: Record[SK]> = {}; for (const [key, argVal] of Object.entries(call.args)) { argSignals[key] = this.resolveSignal(argVal); @@ -202,27 +204,30 @@ export class DataContext { {}, abortController.signal, ); - const sig = result instanceof Signal ? result : signal(result); - (sig as any).unsubscribe = () => abortController.abort(); - return sig; + return this.frameworkSignal.isSignal(result) + ? result + : this.frameworkSignal.wrap(result); } const keys = Object.keys(argSignals); - const resultSig = signal(undefined); + const resultSig = this.frameworkSignal.wrap(undefined); let abortController: AbortController | undefined; let innerUnsubscribe: (() => void) | undefined; - const argsSig = computed(() => { + const argsSig = this.frameworkSignal.computed(() => { const argsRecord: Record = {}; for (let i = 0; i < keys.length; i++) { - argsRecord[keys[i]] = argSignals[keys[i]].value; + argsRecord[keys[i]] = this.frameworkSignal.unwrap( + argSignals[keys[i]], + ); } return argsRecord; }); - const stopper = effect(() => { + const destroy = this.frameworkSignal.effect(() => { try { - const args = argsSig.value; + const args = + this.frameworkSignal.unwrap>(argsSig); if (abortController) abortController.abort(); if (innerUnsubscribe) { innerUnsubscribe(); @@ -230,42 +235,47 @@ export class DataContext { } abortController = new AbortController(); + // Run the function once. The result may be a signal. const res = this.evaluateFunctionReactive( call.call, args, abortController.signal, ); - if (isSignal(res)) { - innerUnsubscribe = effect(() => { - resultSig.value = res.value; + if (this.frameworkSignal.isSignal(res)) { + innerUnsubscribe = this.frameworkSignal.effect(() => { + this.frameworkSignal.set( + resultSig, + this.frameworkSignal.unwrap(res), + ); }); } else { - resultSig.value = res; + this.frameworkSignal.set(resultSig, res); } } catch (e: any) { this.dispatchExpressionError(e, call.call); // In reactive mode, we should not throw. Instead, reset the signal value. - resultSig.value = undefined; + this.frameworkSignal.set(resultSig, undefined); } + + return () => { + if (innerUnsubscribe) innerUnsubscribe(); + if (abortController) abortController.abort(); + }; }); - (resultSig as any).unsubscribe = () => { - stopper(); - if (innerUnsubscribe) innerUnsubscribe(); - if (abortController) abortController.abort(); - for (let i = 0; i < keys.length; i++) { - const argSig = argSignals[keys[i]]; - if ((argSig as any).unsubscribe) { - (argSig as any).unsubscribe(); - } + this.signalCleanups.set(resultSig, () => { + destroy(); + for (const key of Object.keys(argSignals)) { + const childCleanup = this.signalCleanups.get(argSignals[key]); + if (childCleanup) childCleanup(); } - }; + }); - return resultSig as unknown as Signal; + return resultSig; } - return signal(value as unknown as V); + return this.frameworkSignal.wrap(value); } /** @@ -303,12 +313,12 @@ export class DataContext { name: string, args: Record, abortSignal?: AbortSignal, - ): Signal | V { + ): SignalKinds[SK] | V | undefined { try { return this.functionInvoker(name, args, this, abortSignal); } catch (e: any) { this.dispatchExpressionError(e, name); - return undefined as any; + return undefined; } } @@ -352,9 +362,9 @@ export class DataContext { * @param relativePath The path relative to the *current* context's path. * @returns A new `DataContext` instance pointing to the resolved absolute path. */ - nested(relativePath: string): DataContext { + nested(relativePath: string): DataContext { const newPath = this.resolvePath(relativePath); - return new DataContext(this.surface, newPath); + return new DataContext(this.surface, this.frameworkSignal, newPath); } private resolvePath(path: string): string { diff --git a/renderers/web_core/src/v0_9/rendering/generic-binder.test.ts b/renderers/web_core/src/v0_9/rendering/generic-binder.test.ts index 73164755d..059464fef 100644 --- a/renderers/web_core/src/v0_9/rendering/generic-binder.test.ts +++ b/renderers/web_core/src/v0_9/rendering/generic-binder.test.ts @@ -23,12 +23,17 @@ import {SurfaceModel} from '../state/surface-model.js'; import {Catalog} from '../catalog/types.js'; import {ComponentModel} from '../state/component-model.js'; import {CommonSchemas} from '../schema/common-types.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('GenericBinder Checkable Trait', () => { - const mockCatalog = new Catalog('test', [], []); + const mockCatalog = new Catalog('test', [], []); function setupSurfaceAndMocks() { - const surface = new SurfaceModel('s1', mockCatalog); + const surface = new SurfaceModel( + 's1', + mockCatalog, + testFrameworkSignal, + ); // Mock required and min_length functions (surface.catalog as any).functions = new Map([ @@ -79,8 +84,8 @@ describe('GenericBinder Checkable Trait', () => { }); surface.componentsModel.addComponent(compModel); - const context = new ComponentContext(surface, 'c1'); - const binder = new GenericBinder(context, schema); + const context = new ComponentContext(surface, 'c1', testFrameworkSignal); + const binder = new GenericBinder(context, schema); binder.subscribe(() => {}); // Initial state: should be invalid @@ -122,8 +127,12 @@ describe('GenericBinder Checkable Trait', () => { }); surface.componentsModel.addComponent(compModel); - const context = new ComponentContext(surface, 'c2'); - const binder = new GenericBinder(context, schema); + const context = new ComponentContext<'preact'>( + surface, + 'c2', + testFrameworkSignal, + ); + const binder = new GenericBinder(context, schema); binder.subscribe(() => {}); // Both rules fail initially @@ -167,8 +176,8 @@ describe('GenericBinder Checkable Trait', () => { }); surface.componentsModel.addComponent(compModel); - const context = new ComponentContext(surface, 'c3'); - const binder = new GenericBinder(context, schema); + const context = new ComponentContext(surface, 'c3', testFrameworkSignal); + const binder = new GenericBinder(context, schema); assert.strictEqual(binder.snapshot.isValid, false); assert.deepStrictEqual(binder.snapshot.validationErrors, [ @@ -185,8 +194,8 @@ describe('GenericBinder Checkable Trait', () => { }); surface.componentsModel.addComponent(compModel); - const context = new ComponentContext(surface, 'c4'); - const binder = new GenericBinder(context, schema); + const context = new ComponentContext(surface, 'c4', testFrameworkSignal); + const binder = new GenericBinder(context, schema); assert.strictEqual(binder.snapshot.isValid, true); assert.deepStrictEqual(binder.snapshot.validationErrors, []); diff --git a/renderers/web_core/src/v0_9/rendering/generic-binder.ts b/renderers/web_core/src/v0_9/rendering/generic-binder.ts index 6bdb952b8..caef5823d 100644 --- a/renderers/web_core/src/v0_9/rendering/generic-binder.ts +++ b/renderers/web_core/src/v0_9/rendering/generic-binder.ts @@ -22,6 +22,7 @@ import { DataBinding, FunctionCall, } from '../schema/common-types.js'; +import {SignalKinds} from '../reactivity/signals.js'; // --- Schema Scraping --- @@ -189,17 +190,17 @@ export type ResolveA2uiProps = (T extends object * 5. Bundles the final resolved primitives, structural arrays, and executable Actions into `currentProps`. * 6. Exposes a `subscribe()` interface for framework-specific adapters (React, Angular) to listen to state changes. */ -export class GenericBinder { +export class GenericBinder> { private dataListeners: (() => void)[] = []; private propsListeners: ((props: T) => void)[] = []; public currentProps: Partial = {}; private compUnsub?: () => void; private isConnected = false; - private context: ComponentContext; + private context: ComponentContext; private behaviorTree: BehaviorNode; - constructor(context: ComponentContext, schema: z.ZodTypeAny) { + constructor(context: ComponentContext, schema: z.ZodTypeAny) { this.context = context; this.behaviorTree = scrapeSchemaBehavior(schema); diff --git a/renderers/web_core/src/v0_9/state/data-model.test.ts b/renderers/web_core/src/v0_9/state/data-model.test.ts index f29deb9da..b43991735 100644 --- a/renderers/web_core/src/v0_9/state/data-model.test.ts +++ b/renderers/web_core/src/v0_9/state/data-model.test.ts @@ -17,12 +17,13 @@ import assert from 'node:assert'; import {describe, it, beforeEach} from 'node:test'; import {DataModel} from './data-model.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('DataModel', () => { - let model: DataModel; + let model: DataModel<'preact'>; beforeEach(() => { - model = new DataModel({ + model = new DataModel(testFrameworkSignal, { user: { name: 'Alice', settings: { @@ -36,7 +37,7 @@ describe('DataModel', () => { // --- Initialization --- it('initializes with empty data if not provided', () => { - const emptyModel = new DataModel(); + const emptyModel = new DataModel(testFrameworkSignal); assert.deepStrictEqual(emptyModel.get('/'), {}); }); diff --git a/renderers/web_core/src/v0_9/state/data-model.ts b/renderers/web_core/src/v0_9/state/data-model.ts index 67de40e61..0896862ec 100644 --- a/renderers/web_core/src/v0_9/state/data-model.ts +++ b/renderers/web_core/src/v0_9/state/data-model.ts @@ -16,7 +16,11 @@ import {Subscription as BaseSubscription} from '../common/events.js'; import {A2uiDataError} from '../errors.js'; -import {signal, Signal, batch, effect} from '@preact/signals-core'; +import { + FrameworkSignal, + SignalKinds, + WritableSignalKinds, +} from '../reactivity/signals.js'; /** * Represents a reactive connection to a specific path in the data model. @@ -36,9 +40,10 @@ function isNumeric(value: string): boolean { * A standalone, observable data store representing the client-side state. * It handles JSON Pointer path resolution and subscription management. */ -export class DataModel { +export class DataModel> { private data: Record = {}; - private readonly signals: Map> = new Map(); + private readonly signals: Map[SK]> = + new Map(); private readonly subscriptions: Set<() => void> = new Set(); // To track direct subscriptions for dispose /** @@ -46,7 +51,10 @@ export class DataModel { * * @param initialData The initial data for the model. Defaults to an empty object. */ - constructor(initialData: Record = {}) { + constructor( + private readonly frameworkSignal: FrameworkSignal, + initialData: Record = {}, + ) { this.data = initialData; } @@ -59,12 +67,15 @@ export class DataModel { * @param path The JSON pointer path to create or retrieve a signal for. * @returns A Preact Signal representing the value at the specified path. */ - getSignal(path: string): Signal { + getSignal(path: string): SignalKinds[SK] { const normalizedPath = this.normalizePath(path); if (!this.signals.has(normalizedPath)) { - this.signals.set(normalizedPath, signal(this.get(normalizedPath))); + this.signals.set( + normalizedPath, + this.frameworkSignal.wrap(this.get(normalizedPath)), + ); } - return this.signals.get(normalizedPath) as Signal; + return this.signals.get(normalizedPath)!; } /** @@ -187,10 +198,10 @@ export class DataModel { ): DataSubscription { const sig = this.getSignal(path); let isSync = true; - let currentValue = sig.peek(); + let currentValue = this.frameworkSignal.unwrap(sig); - const dispose = effect(() => { - const val = sig.value; + const dispose = this.frameworkSignal.effect(() => { + const val = this.frameworkSignal.unwrap(sig); currentValue = val; if (!isSync) { onChange(val); @@ -236,24 +247,21 @@ export class DataModel { private notifySignals(path: string): void { const normalizedPath = this.normalizePath(path); - batch(() => { - this.updateSignal(normalizedPath); + this.updateSignal(normalizedPath); - // Notify Ancestors - let parentPath = normalizedPath; - while (parentPath !== '/' && parentPath !== '') { - parentPath = - parentPath.substring(0, parentPath.lastIndexOf('/')) || '/'; - this.updateSignal(parentPath); - } + // Notify Ancestors + let parentPath = normalizedPath; + while (parentPath !== '/' && parentPath !== '') { + parentPath = parentPath.substring(0, parentPath.lastIndexOf('/')) || '/'; + this.updateSignal(parentPath); + } - // Notify Descendants - for (const subPath of this.signals.keys()) { - if (this.isDescendant(subPath, normalizedPath)) { - this.updateSignal(subPath); - } + // Notify Descendants + for (const subPath of this.signals.keys()) { + if (this.isDescendant(subPath, normalizedPath)) { + this.updateSignal(subPath); } - }); + } } private updateSignal(path: string): void { @@ -261,21 +269,19 @@ export class DataModel { if (sig) { const val = this.get(path); if (Array.isArray(val)) { - sig.value = [...val]; + this.frameworkSignal.set(sig, [...val]); } else if (typeof val === 'object' && val !== null) { - sig.value = {...val}; + this.frameworkSignal.set(sig, {...val}); } else { - sig.value = val; + this.frameworkSignal.set(sig, val); } } } private notifyAllSignals(): void { - batch(() => { - for (const path of this.signals.keys()) { - this.updateSignal(path); - } - }); + for (const path of this.signals.keys()) { + this.updateSignal(path); + } } private isDescendant(childPath: string, parentPath: string): boolean { diff --git a/renderers/web_core/src/v0_9/state/surface-group-model.test.ts b/renderers/web_core/src/v0_9/state/surface-group-model.test.ts index 4e0afabc6..f89fbfd8c 100644 --- a/renderers/web_core/src/v0_9/state/surface-group-model.test.ts +++ b/renderers/web_core/src/v0_9/state/surface-group-model.test.ts @@ -19,33 +19,34 @@ import {describe, it, beforeEach} from 'node:test'; import {SurfaceGroupModel} from './surface-group-model.js'; import {Catalog, ComponentApi} from '../catalog/types.js'; import {SurfaceModel} from './surface-model.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('SurfaceGroupModel', () => { - let model: SurfaceGroupModel; - let catalog: Catalog; + let model: SurfaceGroupModel; + let catalog: Catalog; beforeEach(() => { - model = new SurfaceGroupModel(); + model = new SurfaceGroupModel(); catalog = new Catalog('test-catalog', []); }); it('adds surface', () => { - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); assert.ok(model.getSurface('s1')); assert.strictEqual(model.getSurface('s1'), surface); }); it('ignores duplicate surface addition', () => { - const s1 = new SurfaceModel('s1', catalog, {}); - const s2 = new SurfaceModel('s1', catalog, {}); // Same ID + const s1 = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); + const s2 = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); // Same ID model.addSurface(s1); model.addSurface(s2); assert.strictEqual(model.getSurface('s1'), s1); // Should still be the first one }); it('deletes surface', () => { - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); assert.ok(model.getSurface('s1')); @@ -54,7 +55,7 @@ describe('SurfaceGroupModel', () => { }); it('notifies lifecycle listeners', () => { - let created: SurfaceModel | undefined; + let created: SurfaceModel | undefined; let deletedId: string | undefined; model.onSurfaceCreated.subscribe(s => { @@ -64,7 +65,7 @@ describe('SurfaceGroupModel', () => { deletedId = id; }); - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); assert.ok(created); assert.strictEqual(created?.id, 's1'); @@ -79,7 +80,7 @@ describe('SurfaceGroupModel', () => { receivedAction = action; }); - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); await surface.dispatchAction({event: {name: 'test'}}, 'c1'); @@ -94,7 +95,7 @@ describe('SurfaceGroupModel', () => { callCount++; }); - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); model.deleteSurface('s1'); @@ -103,7 +104,7 @@ describe('SurfaceGroupModel', () => { }); it('exposes surfacesMap', () => { - const surface = new SurfaceModel('s1', catalog, {}); + const surface = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); model.addSurface(surface); const map = model.surfacesMap; assert.strictEqual(map.size, 1); @@ -111,8 +112,8 @@ describe('SurfaceGroupModel', () => { }); it('disposes correctly', () => { - const s1 = new SurfaceModel('s1', catalog, {}); - const s2 = new SurfaceModel('s2', catalog, {}); + const s1 = new SurfaceModel('s1', catalog, testFrameworkSignal, {}); + const s2 = new SurfaceModel('s2', catalog, testFrameworkSignal, {}); model.addSurface(s1); model.addSurface(s2); diff --git a/renderers/web_core/src/v0_9/state/surface-group-model.ts b/renderers/web_core/src/v0_9/state/surface-group-model.ts index b8c02042d..6f6c29517 100644 --- a/renderers/web_core/src/v0_9/state/surface-group-model.ts +++ b/renderers/web_core/src/v0_9/state/surface-group-model.ts @@ -18,21 +18,25 @@ import {SurfaceModel} from './surface-model.js'; import {ComponentApi} from '../catalog/types.js'; import {EventEmitter, EventSource, Subscription} from '../common/events.js'; import {A2uiClientAction} from '../schema/client-to-server.js'; +import {SignalKinds} from '../reactivity/signals.js'; /** * The root state model for the A2UI system. * Manages the collection of active surfaces. */ -export class SurfaceGroupModel { - private surfaces: Map> = new Map(); +export class SurfaceGroupModel< + T extends ComponentApi, + SK extends keyof SignalKinds, +> { + private surfaces: Map> = new Map(); private surfaceUnsubscribers: Map = new Map(); - private readonly _onSurfaceCreated = new EventEmitter>(); + private readonly _onSurfaceCreated = new EventEmitter>(); private readonly _onSurfaceDeleted = new EventEmitter(); private readonly _onAction = new EventEmitter(); /** Fires when a new surface is added. */ - readonly onSurfaceCreated: EventSource> = + readonly onSurfaceCreated: EventSource> = this._onSurfaceCreated; /** Fires when a surface is removed. */ readonly onSurfaceDeleted: EventSource = this._onSurfaceDeleted; @@ -45,7 +49,7 @@ export class SurfaceGroupModel { * * @param surface The surface model to add. */ - addSurface(surface: SurfaceModel): void { + addSurface(surface: SurfaceModel): void { if (this.surfaces.has(surface.id)) { console.warn(`Surface ${surface.id} already exists. Ignoring.`); return; @@ -90,14 +94,14 @@ export class SurfaceGroupModel { * @param id The ID of the surface to retrieve. * @returns The surface model, or undefined if not found. */ - getSurface(id: string): SurfaceModel | undefined { + getSurface(id: string): SurfaceModel | undefined { return this.surfaces.get(id); } /** * Returns a readonly map of all active surfaces. */ - get surfacesMap(): ReadonlyMap> { + get surfacesMap(): ReadonlyMap> { return this.surfaces; } diff --git a/renderers/web_core/src/v0_9/state/surface-model.test.ts b/renderers/web_core/src/v0_9/state/surface-model.test.ts index d785a774c..3f2b812c7 100644 --- a/renderers/web_core/src/v0_9/state/surface-model.test.ts +++ b/renderers/web_core/src/v0_9/state/surface-model.test.ts @@ -20,10 +20,11 @@ import {SurfaceModel} from './surface-model.js'; import {Catalog, ComponentApi} from '../catalog/types.js'; import {ComponentModel} from './component-model.js'; import {ComponentContext} from '../rendering/component-context.js'; +import {testFrameworkSignal} from '../test/test_signals.js'; describe('SurfaceModel', () => { - let surface: SurfaceModel; - let catalog: Catalog; + let surface: SurfaceModel; + let catalog: Catalog; let actions: any[] = []; let errors: any[] = []; @@ -31,7 +32,7 @@ describe('SurfaceModel', () => { actions = []; errors = []; catalog = new Catalog('test-catalog', []); - surface = new SurfaceModel('surface-1', catalog, {}); + surface = new SurfaceModel('surface-1', catalog, testFrameworkSignal, {}); surface.onAction.subscribe(async action => { actions.push(action); }); @@ -85,7 +86,12 @@ describe('SurfaceModel', () => { it('creates a component context', () => { surface.componentsModel.addComponent(new ComponentModel('root', 'Box', {})); - const ctx = new ComponentContext(surface, 'root', '/mydata'); + const ctx = new ComponentContext( + surface, + 'root', + testFrameworkSignal, + '/mydata', + ); assert.ok(ctx); assert.strictEqual(ctx.dataContext.path, '/mydata'); }); diff --git a/renderers/web_core/src/v0_9/state/surface-model.ts b/renderers/web_core/src/v0_9/state/surface-model.ts index 1d6befafa..f6e65d84f 100644 --- a/renderers/web_core/src/v0_9/state/surface-model.ts +++ b/renderers/web_core/src/v0_9/state/surface-model.ts @@ -22,6 +22,7 @@ import { A2uiClientAction, A2uiClientActionSchema, } from '../schema/client-to-server.js'; +import {FrameworkSignal, SignalKinds} from '../reactivity/signals.js'; /** A function that listens for actions emitted from a surface. */ export type ActionListener = (action: A2uiClientAction) => void | Promise; @@ -34,9 +35,12 @@ export type ActionListener = (action: A2uiClientAction) => void | Promise; * * @template T The concrete type of the ComponentApi from the catalog. */ -export class SurfaceModel { +export class SurfaceModel< + T extends ComponentApi, + SK extends keyof SignalKinds, +> { /** The data model for this surface. */ - readonly dataModel: DataModel; + readonly dataModel: DataModel; /** The collection of component models for this surface. */ readonly componentsModel: SurfaceComponentsModel; @@ -59,11 +63,12 @@ export class SurfaceModel { */ constructor( readonly id: string, - readonly catalog: Catalog, + readonly catalog: Catalog, + frameworkSignal: FrameworkSignal, readonly theme: any = {}, readonly sendDataModel: boolean = false, ) { - this.dataModel = new DataModel({}); + this.dataModel = new DataModel(frameworkSignal, {}); this.componentsModel = new SurfaceComponentsModel(); } diff --git a/renderers/web_core/src/v0_9/test/function_execution.spec.ts b/renderers/web_core/src/v0_9/test/function_execution.spec.ts index 88f421c6d..f5d00b22c 100644 --- a/renderers/web_core/src/v0_9/test/function_execution.spec.ts +++ b/renderers/web_core/src/v0_9/test/function_execution.spec.ts @@ -18,11 +18,10 @@ import {describe, it} from 'node:test'; import assert from 'node:assert'; import {DataModel} from '../state/data-model.js'; import {DataContext} from '../rendering/data-context.js'; - -import {signal} from '@preact/signals-core'; +import {testFrameworkSignal} from './test_signals.js'; const createTestDataContext = ( - model: DataModel, + model: DataModel<'preact'>, path: string, functionInvoker: any = () => null, ) => { @@ -31,12 +30,12 @@ const createTestDataContext = ( catalog: {invoker: functionInvoker}, dispatchError: () => {}, } as any; - return new DataContext(mockSurface, path); + return new DataContext(mockSurface, testFrameworkSignal, path); }; describe('Function Execution in DataContext', () => { it('resolves and subscribes to metronome function', () => { - const dataModel = new DataModel(); + const dataModel = new DataModel(testFrameworkSignal); const functions = new Map(); // mimic metronome: returns a stream of ticks @@ -44,10 +43,10 @@ describe('Function Execution in DataContext', () => { 'metronome', (args: Record, abortSignal?: AbortSignal) => { const interval = Number(args['interval']) || 100; - const subj = signal('tick 0'); + const subj = testFrameworkSignal.wrap('tick 0'); let i = 1; const timerId = setInterval(() => { - subj.value = `tick ${i++}`; + testFrameworkSignal.set(subj, `tick ${i++}`); }, interval); abortSignal?.addEventListener('abort', () => { @@ -102,7 +101,7 @@ describe('Function Execution in DataContext', () => { }); it('updates function output when arguments change', () => { - const dataModel = new DataModel(); + const dataModel = new DataModel(testFrameworkSignal); const functions = new Map(); functions.set('echo', (args: Record) => { diff --git a/renderers/web_core/src/v0_9/test/test-utils.ts b/renderers/web_core/src/v0_9/test/test-utils.ts index 87e148c26..68c844b9f 100644 --- a/renderers/web_core/src/v0_9/test/test-utils.ts +++ b/renderers/web_core/src/v0_9/test/test-utils.ts @@ -18,10 +18,11 @@ import {ComponentContext} from '../rendering/component-context.js'; import {SurfaceModel} from '../state/surface-model.js'; import {Catalog, ComponentApi} from '../catalog/types.js'; import {ComponentModel} from '../state/component-model.js'; +import {testFrameworkSignal} from './test_signals.js'; -export class TestSurfaceModel extends SurfaceModel { +export class TestSurfaceModel extends SurfaceModel { constructor(actionHandler: any = async () => {}) { - super('test', new Catalog('test-catalog', []), {}); + super('test', new Catalog('test-catalog', []), testFrameworkSignal, {}); this.onAction.subscribe(actionHandler); } } @@ -34,7 +35,12 @@ export function createTestContext( const component = new ComponentModel('test-id', 'TestComponent', properties); surface.componentsModel.addComponent(component); - const context = new ComponentContext(surface, 'test-id', '/'); + const context = new ComponentContext( + surface, + 'test-id', + testFrameworkSignal, + '/', + ); return context; } diff --git a/renderers/web_core/src/v0_9/test/test_signals.ts b/renderers/web_core/src/v0_9/test/test_signals.ts new file mode 100644 index 000000000..3a8153cf1 --- /dev/null +++ b/renderers/web_core/src/v0_9/test/test_signals.ts @@ -0,0 +1,41 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Signal, computed, effect} from '@preact/signals-core'; +import {FrameworkSignal} from '../reactivity/signals.js'; + +declare module '../reactivity/signals' { + interface SignalKinds { + preact: Signal; + } + interface WritableSignalKinds { + preact: Signal; + } +} + +/** + * Simple implementation of FrameworkSignal for use in tests. + */ +export const testFrameworkSignal: FrameworkSignal<'preact'> = { + computed: (fn: () => T) => computed(fn), + effect: (fn: () => void) => effect(fn), + isSignal: (val: unknown) => val instanceof Signal, + wrap: (val: T) => new Signal(val), + unwrap: (val: Signal) => val.value, + set: (signal: Signal, value: T) => { + signal.value = value; + }, +};