diff --git a/.github/workflows/react_renderer.yml b/.github/workflows/react_renderer.yml
index 0732db2ad..50323d3b7 100644
--- a/.github/workflows/react_renderer.yml
+++ b/.github/workflows/react_renderer.yml
@@ -58,6 +58,36 @@ jobs:
- name: Test React renderer
working-directory: ./renderers/react
run: npm test
+
+ build-and-test-demo:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: '20'
+
+ - name: Build web_core dependency
+ working-directory: ./renderers/web_core
+ run: |
+ npm ci
+ npm run build
+
+ - name: Install React renderer deps
+ working-directory: ./renderers/react
+ run: npm ci
+
+ - name: Build React Demo
+ working-directory: ./renderers/react
+ run: npm run build:demo
+
+ - name: Test React Demo
+ working-directory: ./renderers/react
+ run: npm run test:demo
+
lint:
runs-on: ubuntu-latest
diff --git a/renderers/react/a2ui_explorer/README.md b/renderers/react/a2ui_explorer/README.md
new file mode 100644
index 000000000..2b04a3e15
--- /dev/null
+++ b/renderers/react/a2ui_explorer/README.md
@@ -0,0 +1,62 @@
+# A2UI React Gallery App
+
+This is the reference Gallery Application for the A2UI React renderer. It allows you to explore A2UI samples, inspect the live data model, and step through the message rendering process.
+
+## Prerequisites
+
+This application depends on the following local libraries in this repository:
+1. `@a2ui/web_core` (located in `renderers/web_core`)
+2. `@a2ui/react` (located in `renderers/react`)
+
+## Building Dependencies
+
+Before running the gallery app, you must build the local renderer library:
+
+```bash
+# Navigate to the React renderer library
+cd ../..
+
+# Install and build the library
+npm install
+npm run build
+```
+
+*Note: Ensure `@a2ui/web_core` is also built if you have made changes to the core logic.*
+
+## Setup and Development
+
+Once the dependencies are built, you can start the gallery app:
+
+```bash
+# Navigate to this directory
+cd renderers/react/a2ui_explorer
+
+# Install dependencies
+npm install
+
+# Start the development server
+npm run dev
+```
+
+## Building for Production
+
+To create a production build of the gallery app:
+
+```bash
+npm run build
+```
+
+## Running Tests
+
+To run the integration tests:
+
+```bash
+npm test
+```
+
+## Gallery Features
+
+- **3-Column Layout**: Left (Sample selection), Center (Live preview & Message stepper), Right (Data model & Action logs).
+- **Progressive Stepper**: Use the "Advance" buttons next to each JSON message to see how the UI builds up incrementally.
+- **Action Logs**: View real-time logs of actions triggered by user interactions.
+- **Data Model Inspector**: Observe how the surface's data model changes as you interact with form fields.
diff --git a/renderers/react/a2ui_explorer/eslint.config.js b/renderers/react/a2ui_explorer/eslint.config.js
new file mode 100644
index 000000000..dcc74559c
--- /dev/null
+++ b/renderers/react/a2ui_explorer/eslint.config.js
@@ -0,0 +1,105 @@
+/**
+ * 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 globals from 'globals';
+import tseslint from 'typescript-eslint';
+import reactHooksPlugin from 'eslint-plugin-react-hooks';
+import reactRefreshPlugin from 'eslint-plugin-react-refresh';
+import prettierConfig from 'eslint-config-prettier';
+import gts from 'gts';
+
+export default tseslint.config(
+ // Google TypeScript style guide plugin.
+ ...gts.map(config => ({
+ ...config,
+ // Override the project for a2ui_explorer since it has its own tsconfig
+ ...(config.languageOptions?.parserOptions?.project ? {
+ languageOptions: {
+ ...config.languageOptions,
+ parserOptions: {
+ ...config.languageOptions.parserOptions,
+ project: ['./tsconfig.app.json', './tsconfig.node.json']
+ }
+ }
+ } : {})
+ })),
+
+ {
+ files: ['**/*.{ts,tsx}'],
+ plugins: {
+ 'react-hooks': reactHooksPlugin,
+ 'react-refresh': reactRefreshPlugin,
+ },
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: {
+ ...globals.browser,
+ },
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ },
+ rules: {
+ // React Hooks rules (errors)
+ ...reactHooksPlugin.configs.recommended.rules,
+
+ // React Refresh rules
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+
+ // TypeScript rules
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ {
+ argsIgnorePattern: '^_',
+ varsIgnorePattern: '^_',
+ },
+ ],
+ '@typescript-eslint/no-explicit-any': 'warn',
+ '@typescript-eslint/consistent-type-imports': [
+ 'warn',
+ {
+ prefer: 'type-imports',
+ fixStyle: 'inline-type-imports',
+ },
+ ],
+
+ // General rules
+ 'no-console': ['warn', { allow: ['warn', 'error'] }],
+ 'prefer-arrow-callback': 'off',
+ },
+ },
+
+ // Test files - relaxed rules
+ {
+ files: ['tests/**/*.{ts,tsx}', '**/*.test.{ts,tsx}', 'src/setupTests.ts'],
+ rules: {
+ '@typescript-eslint/no-explicit-any': 'off',
+ 'no-console': 'off',
+ },
+ },
+
+ // Prettier config
+ prettierConfig,
+
+ {
+ ignores: ['dist/**', 'node_modules/**', '**/*.d.ts'],
+ }
+);
diff --git a/renderers/react/a2ui_explorer/index.html b/renderers/react/a2ui_explorer/index.html
new file mode 100644
index 000000000..77fa01208
--- /dev/null
+++ b/renderers/react/a2ui_explorer/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+ react
+
+
+
+
+
+
diff --git a/renderers/react/a2ui_explorer/package-lock.json b/renderers/react/a2ui_explorer/package-lock.json
new file mode 100644
index 000000000..c99958301
--- /dev/null
+++ b/renderers/react/a2ui_explorer/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "a2ui_explorer",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}
diff --git a/renderers/react/a2ui_explorer/public/vite.svg b/renderers/react/a2ui_explorer/public/vite.svg
new file mode 100644
index 000000000..e7b8dfb1b
--- /dev/null
+++ b/renderers/react/a2ui_explorer/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/renderers/react/a2ui_explorer/src/App.css b/renderers/react/a2ui_explorer/src/App.css
new file mode 100644
index 000000000..72984a9f1
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/App.css
@@ -0,0 +1,58 @@
+/**
+ * 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.
+ */
+
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .logo.react {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/renderers/react/a2ui_explorer/src/App.tsx b/renderers/react/a2ui_explorer/src/App.tsx
new file mode 100644
index 000000000..7b42ceee4
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/App.tsx
@@ -0,0 +1,377 @@
+/**
+ * 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 {useState, useEffect, useSyncExternalStore, useCallback} from 'react';
+import {MessageProcessor, SurfaceModel, type A2uiMessage} from '@a2ui/web_core/v0_9';
+import {minimalCatalog, A2uiSurface, type ReactComponentImplementation} from '@a2ui/react/v0_9';
+
+// Import Minimal examples
+import min1 from '../../../../specification/v0_9/json/catalogs/minimal/examples/1_simple_text.json';
+import min2 from '../../../../specification/v0_9/json/catalogs/minimal/examples/2_row_layout.json';
+import min3 from '../../../../specification/v0_9/json/catalogs/minimal/examples/3_interactive_button.json';
+import min4 from '../../../../specification/v0_9/json/catalogs/minimal/examples/4_login_form.json';
+import min5 from '../../../../specification/v0_9/json/catalogs/minimal/examples/5_complex_layout.json';
+import min6 from '../../../../specification/v0_9/json/catalogs/minimal/examples/6_capitalized_text.json';
+import min7 from '../../../../specification/v0_9/json/catalogs/minimal/examples/7_incremental.json';
+
+const exampleFiles = [
+ {key: 'min1', data: min1, catalog: 'Minimal'},
+ {key: 'min2', data: min2, catalog: 'Minimal'},
+ {key: 'min3', data: min3, catalog: 'Minimal'},
+ {key: 'min4', data: min4, catalog: 'Minimal'},
+ {key: 'min5', data: min5, catalog: 'Minimal'},
+ {key: 'min6', data: min6, catalog: 'Minimal'},
+ {key: 'min7', data: min7, catalog: 'Minimal'},
+];
+
+const getMessages = (ex: { messages: A2uiMessage[] } | A2uiMessage[] | undefined) => (Array.isArray(ex) ? ex : ex?.messages);
+
+const DataModelViewer = ({surface}: {surface: SurfaceModel}) => {
+ const subscribeHook = useCallback(
+ (callback: () => void) => {
+ const bound = surface.dataModel.subscribe('/', callback);
+ return () => bound.unsubscribe();
+ },
+ [surface]
+ );
+
+ const getSnapshot = useCallback(() => {
+ return JSON.stringify(surface.dataModel.get('/'), null, 2);
+ }, [surface]);
+
+ const dataString = useSyncExternalStore(subscribeHook, getSnapshot);
+
+ return (
+
+
Surface: {surface.id}
+
{dataString}
+
+ );
+};
+
+export default function App() {
+ const [selectedExampleKey, setSelectedExampleKey] = useState(exampleFiles[0].key);
+ const selectedExample = exampleFiles.find((e) => e.key === selectedExampleKey)?.data as any;
+
+ const [logs, setLogs] = useState([]);
+ const [processor, setProcessor] = useState | null>(null);
+ const [surfaces, setSurfaces] = useState([]);
+ const [currentMessageIndex, setCurrentMessageIndex] = useState(-1);
+
+ // Initialize or reset processor
+ const resetProcessor = useCallback(
+ (advanceToEnd: boolean = false) => {
+ setProcessor((prevProcessor) => {
+ if (prevProcessor) {
+ prevProcessor.model.dispose();
+ }
+ const newProcessor = new MessageProcessor([minimalCatalog], async (action: any) => {
+ setLogs((l) => [...l, {time: new Date().toISOString(), action}]);
+ });
+
+ const msgs = getMessages(selectedExample);
+ if (advanceToEnd && msgs) {
+ newProcessor.processMessages(msgs);
+ }
+ return newProcessor;
+ });
+
+ setLogs([]);
+ setSurfaces([]);
+
+ const msgs = getMessages(selectedExample);
+ if (advanceToEnd && msgs) {
+ setCurrentMessageIndex(msgs.length - 1);
+ } else {
+ setCurrentMessageIndex(-1);
+ }
+ },
+ [selectedExample]
+ );
+
+ // Effect to handle example selection change
+ useEffect(() => {
+ resetProcessor(true);
+ // Cleanup on unmount or when changing examples
+ return () => {
+ setProcessor((prev) => {
+ if (prev) prev.model.dispose();
+ return null;
+ });
+ };
+ }, [selectedExampleKey, resetProcessor]);
+
+ // Handle surface subscriptions
+ useEffect(() => {
+ if (!processor) {
+ setSurfaces([]);
+ return;
+ }
+
+ const updateSurfaces = () => {
+ setSurfaces(Array.from(processor.model.surfacesMap.values()).map((s: any) => s.id as string));
+ };
+
+ updateSurfaces();
+
+ const unsub1 = processor.model.onSurfaceCreated.subscribe(updateSurfaces);
+ const unsub2 = processor.model.onSurfaceDeleted.subscribe(updateSurfaces);
+
+ return () => {
+ unsub1.unsubscribe();
+ unsub2.unsubscribe();
+ };
+ }, [processor]);
+
+ const advanceToMessage = (index: number) => {
+ const msgs = getMessages(selectedExample);
+ if (!processor || !msgs) return;
+
+ // Process messages from currentMessageIndex + 1 to index
+ const messagesToProcess = msgs.slice(currentMessageIndex + 1, index + 1);
+ if (messagesToProcess.length > 0) {
+ processor.processMessages(messagesToProcess);
+ setCurrentMessageIndex(index);
+ }
+ };
+
+ const handleReset = () => {
+ resetProcessor(false);
+ };
+
+ const messages = getMessages(selectedExample) || [];
+
+ return (
+
+ {/* Left Column: Sample List */}
+
+
Samples
+
+ {exampleFiles.map((ex) => (
+
+ setSelectedExampleKey(ex.key)}
+ style={{
+ width: '100%',
+ textAlign: 'left',
+ fontWeight: selectedExampleKey === ex.key ? 'bold' : 'normal',
+ background: selectedExampleKey === ex.key ? '#eee' : '#fafafa',
+ color: '#000',
+ border: '1px solid #ccc',
+ padding: '8px',
+ borderRadius: '4px',
+ cursor: 'pointer',
+ }}
+ >
+ {ex.catalog}
+ {(ex.data as any).name || ex.key}
+
+
+ ))}
+
+
+
+ {/* Center Column: Preview & JSON Stepper */}
+
+
+
Preview
+ {surfaces.length === 0 && (
+
No surfaces loaded. Advance the stepper to create one.
+ )}
+ {surfaces.map((surfaceId) => {
+ const surface = processor?.model.getSurface(surfaceId);
+ if (!surface) return null;
+ return (
+
+ );
+ })}
+
+
+
+
+
Messages
+
+ Reset
+
+
+
+
+ {messages.map((msg: any, i: number) => {
+ const isActive = i <= currentMessageIndex;
+ return (
+
+
+ Message {i + 1}
+ {!isActive && (
+ advanceToMessage(i)}
+ style={{padding: '2px 8px', cursor: 'pointer'}}
+ >
+ Advance
+
+ )}
+
+
+ {JSON.stringify(msg, null, 2)}
+
+
+ );
+ })}
+
+
+
+
+ {/* Right Column: Live DataModelViewer & Action Logs */}
+
+
+
Data Model
+
+ {surfaces.length === 0 ? (
+
Empty Data Model
+ ) : null}
+ {surfaces.map((surfaceId) => {
+ const surface = processor?.model.getSurface(surfaceId);
+ if (!surface) return null;
+ return
;
+ })}
+
+
+
+
+
Action Logs
+
+ {logs.length === 0 ? (
+
No actions logged yet.
+ ) : null}
+ {logs.map((log, i) => (
+
+
{log.time}
+
+ {JSON.stringify(log.action, null, 2)}
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/renderers/react/a2ui_explorer/src/assets/react.svg b/renderers/react/a2ui_explorer/src/assets/react.svg
new file mode 100644
index 000000000..6c87de9bb
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/renderers/react/a2ui_explorer/src/index.css b/renderers/react/a2ui_explorer/src/index.css
new file mode 100644
index 000000000..b0c6a5ca1
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/index.css
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+
+:root {
+ font-family: system-ui, -apple-system, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/renderers/react/a2ui_explorer/src/integration.test.tsx b/renderers/react/a2ui_explorer/src/integration.test.tsx
new file mode 100644
index 000000000..0f142d0da
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/integration.test.tsx
@@ -0,0 +1,83 @@
+/**
+ * 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 {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 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';
+import ex4 from '../../../../specification/v0_9/json/catalogs/minimal/examples/4_login_form.json';
+
+describe('Gallery Integration Tests', () => {
+ it('renders Simple Text -> "Hello Minimal Catalog"', async () => {
+ const processor = new MessageProcessor([minimalCatalog as any], async () => {});
+ processor.processMessages(ex1.messages as any[]);
+
+ const surface = processor.model.getSurface('example_1');
+ expect(surface).toBeDefined();
+
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('Hello, Minimal Catalog!')).toBeInTheDocument();
+ });
+
+ it('renders Row layout -> content visibility', async () => {
+ const processor = new MessageProcessor([minimalCatalog as any], async () => {});
+ processor.processMessages(ex2.messages as any[]);
+
+ const surface = processor.model.getSurface('example_2');
+ expect(surface).toBeDefined();
+
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('Left Content')).toBeInTheDocument();
+ expect(screen.getByText('Right Content')).toBeInTheDocument();
+ });
+
+ it('handles Login form -> input updates data model', async () => {
+ const processor = new MessageProcessor([minimalCatalog as any], async () => {});
+ processor.processMessages(ex4.messages as any[]);
+
+ const surface = processor.model.getSurface('example_4');
+ expect(surface).toBeDefined();
+
+ render(
+
+
+
+ );
+
+ const usernameInput = screen.getByLabelText('Username') as HTMLInputElement;
+ expect(usernameInput).toBeDefined();
+
+ await act(async () => {
+ fireEvent.change(usernameInput, {target: {value: 'alice'}});
+ });
+
+ expect(surface!.dataModel.get('/username')).toBe('alice');
+ });
+});
diff --git a/renderers/react/a2ui_explorer/src/main.tsx b/renderers/react/a2ui_explorer/src/main.tsx
new file mode 100644
index 000000000..e4ce6a0d6
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/main.tsx
@@ -0,0 +1,26 @@
+/**
+ * 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 {StrictMode} from 'react';
+import {createRoot} from 'react-dom/client';
+import './index.css';
+import App from './App.tsx';
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+);
diff --git a/renderers/react/a2ui_explorer/src/setupTests.ts b/renderers/react/a2ui_explorer/src/setupTests.ts
new file mode 100644
index 000000000..5816a5872
--- /dev/null
+++ b/renderers/react/a2ui_explorer/src/setupTests.ts
@@ -0,0 +1,17 @@
+/**
+ * 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 '@testing-library/jest-dom';
diff --git a/renderers/react/a2ui_explorer/tsconfig.app.json b/renderers/react/a2ui_explorer/tsconfig.app.json
new file mode 100644
index 000000000..d57468003
--- /dev/null
+++ b/renderers/react/a2ui_explorer/tsconfig.app.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "types": ["vite/client"],
+ "skipLibCheck": true,
+
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "resolveJsonModule": true,
+
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true,
+ "paths": {
+ "@a2ui/react": ["../src/index.ts"],
+ "@a2ui/react/*": ["../src/*"]
+ }
+ },
+ "include": ["src"]
+}
diff --git a/renderers/react/a2ui_explorer/tsconfig.json b/renderers/react/a2ui_explorer/tsconfig.json
new file mode 100644
index 000000000..1ffef600d
--- /dev/null
+++ b/renderers/react/a2ui_explorer/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/renderers/react/a2ui_explorer/tsconfig.node.json b/renderers/react/a2ui_explorer/tsconfig.node.json
new file mode 100644
index 000000000..8a67f62f4
--- /dev/null
+++ b/renderers/react/a2ui_explorer/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2023",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "types": ["node"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/renderers/react/a2ui_explorer/vite.config.ts b/renderers/react/a2ui_explorer/vite.config.ts
new file mode 100644
index 000000000..e0ba24985
--- /dev/null
+++ b/renderers/react/a2ui_explorer/vite.config.ts
@@ -0,0 +1,38 @@
+/**
+ * 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 { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+import { resolve } from 'path'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ '@a2ui/react/v0_9': resolve(__dirname, '../src/v0_9/index.ts'),
+ '@a2ui/react/v0_8': resolve(__dirname, '../src/v0_8/index.ts'),
+ '@a2ui/react/styles': resolve(__dirname, '../src/styles/index.ts'),
+ '@a2ui/react': resolve(__dirname, '../src/index.ts')
+ }
+ },
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ setupFiles: ['./src/setupTests.ts']
+ }
+} as any)
diff --git a/renderers/react/eslint.config.js b/renderers/react/eslint.config.js
index c8a26f23d..88d2293a3 100644
--- a/renderers/react/eslint.config.js
+++ b/renderers/react/eslint.config.js
@@ -22,12 +22,6 @@ import prettierConfig from 'eslint-config-prettier';
import gts from 'gts';
export default tseslint.config(
- // Base JS recommended rules
- js.configs.recommended,
-
- // TypeScript recommended rules
- ...tseslint.configs.recommended,
-
// Google TypeScript style guide plugin.
// See: https://github.com/google/gts
// And: https://google.github.io/styleguide/tsguide.html
@@ -82,8 +76,6 @@ export default tseslint.config(
// General rules
'no-console': ['warn', { allow: ['warn', 'error'] }],
- 'prefer-const': 'error',
- 'no-var': 'error',
'prefer-arrow-callback': 'off',
},
},
diff --git a/renderers/react/package-lock.json b/renderers/react/package-lock.json
index 84d00d668..8ad0f6a90 100644
--- a/renderers/react/package-lock.json
+++ b/renderers/react/package-lock.json
@@ -11,27 +11,36 @@
"dependencies": {
"@a2ui/web_core": "file:../web_core",
"clsx": "^2.1.0",
- "markdown-it": "^14.0.0"
+ "markdown-it": "^14.0.0",
+ "rxjs": "^7.8.1",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"@testing-library/jest-dom": "^6.6.0",
"@testing-library/react": "^16.0.0",
"@types/markdown-it": "^14.1.0",
+ "@types/node": "^24.10.1",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
+ "@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-react": "^7.37.0",
"eslint-plugin-react-hooks": "^5.0.0",
+ "eslint-plugin-react-refresh": "^0.4.24",
+ "globals": "^16.5.0",
"gts": "^7.0.0",
"jsdom": "^28.0.0",
"prettier": "^3.4.0",
+ "puppeteer": "^24.39.0",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"tsup": "^8.0.0",
+ "tsx": "^4.21.0",
"typescript": "^5.8.0",
"typescript-eslint": "^8.0.0",
+ "vite": "^7.3.1",
"vitest": "^4.0.18"
},
"engines": {
@@ -127,8 +136,9 @@
"license": "MIT"
},
"node_modules/@babel/code-frame": {
- "version": "7.28.6",
- "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -140,6 +150,160 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.28.6",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "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",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
@@ -149,6 +313,78 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
+ "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.28.6",
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
@@ -158,6 +394,54 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/template": {
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@csstools/color-helpers": {
"version": "5.1.0",
"integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
@@ -800,6 +1084,19 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@eslint/js": {
"version": "9.39.2",
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
@@ -909,6 +1206,17 @@
"@jridgewell/trace-mapping": "^0.3.24"
}
},
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
@@ -946,6 +1254,48 @@
"url": "https://opencollective.com/pkgr"
}
},
+ "node_modules/@puppeteer/browsers": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz",
+ "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "extract-zip": "^2.0.1",
+ "progress": "^2.0.3",
+ "proxy-agent": "^6.5.0",
+ "semver": "^7.7.4",
+ "tar-fs": "^3.1.1",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "browsers": "lib/cjs/main-cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@puppeteer/browsers/node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-rc.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
+ "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.57.1",
"integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==",
@@ -1349,6 +1699,13 @@
}
}
},
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/aria-query": {
"version": "5.0.4",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
@@ -1356,6 +1713,51 @@
"license": "MIT",
"peer": true
},
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
"node_modules/@types/chai": {
"version": "5.2.3",
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
@@ -1412,6 +1814,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/node": {
+ "version": "24.12.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz",
+ "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
@@ -1443,6 +1855,17 @@
"@types/react": "^18.0.0"
}
},
+ "node_modules/@types/yauzl": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+ "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.54.0",
"integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
@@ -1698,6 +2121,27 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@vitejs/plugin-react": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz",
+ "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.29.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-rc.3",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.18.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
"node_modules/@vitest/expect": {
"version": "4.0.18",
"integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==",
@@ -2054,6 +2498,19 @@
"node": ">=12"
}
},
+ "node_modules/ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+ "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/async-function": {
"version": "1.0.0",
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
@@ -2084,13 +2541,129 @@
"dev": true,
"license": "MIT"
},
- "node_modules/bidi-js": {
- "version": "1.0.3",
- "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "node_modules/bare-events": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
+ "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "require-from-string": "^2.0.2"
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "bare-abort-controller": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-fs": {
+ "version": "4.5.6",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz",
+ "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.5.4",
+ "bare-path": "^3.0.0",
+ "bare-stream": "^2.6.4",
+ "bare-url": "^2.2.2",
+ "fast-fifo": "^1.3.2"
+ },
+ "engines": {
+ "bare": ">=1.16.0"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-os": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz",
+ "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "bare": ">=1.14.0"
+ }
+ },
+ "node_modules/bare-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
+ "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-os": "^3.0.1"
+ }
+ },
+ "node_modules/bare-stream": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.10.0.tgz",
+ "integrity": "sha512-DOPZF/DDcDruKDA43cOw6e9Quq5daua7ygcAwJE/pKJsRWhgSSemi7qVNGE5kyDIxIeN1533G/zfbvWX7Wcb9w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "streamx": "^2.25.0",
+ "teex": "^1.0.1"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*",
+ "bare-events": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ },
+ "bare-events": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-url": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
+ "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-path": "^3.0.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.9",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz",
+ "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/basic-ftp": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz",
+ "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/bidi-js": {
+ "version": "1.0.3",
+ "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "require-from-string": "^2.0.2"
}
},
"node_modules/brace-expansion": {
@@ -2103,6 +2676,50 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/browserslist": {
+ "version": "4.28.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "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"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/bundle-require": {
"version": "5.1.0",
"integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==",
@@ -2209,6 +2826,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001780",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz",
+ "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
"node_modules/chai": {
"version": "6.2.2",
"integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
@@ -2270,6 +2908,20 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/chromium-bidi": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz",
+ "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "mitt": "^3.0.1",
+ "zod": "^3.24.1"
+ },
+ "peerDependencies": {
+ "devtools-protocol": "*"
+ }
+ },
"node_modules/cli-cursor": {
"version": "3.1.0",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
@@ -2291,6 +2943,21 @@
"node": ">= 10"
}
},
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/clsx": {
"version": "2.1.1",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
@@ -2347,6 +3014,40 @@
"node": "^14.18.0 || >=16.10.0"
}
},
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cosmiconfig": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz",
+ "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
@@ -2401,6 +3102,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/data-urls": {
"version": "7.0.0",
"integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==",
@@ -2562,6 +3273,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/degenerator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.13.4",
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/dequal": {
"version": "2.0.3",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
@@ -2571,6 +3297,13 @@
"node": ">=6"
}
},
+ "node_modules/devtools-protocol": {
+ "version": "0.0.1581282",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1581282.tgz",
+ "integrity": "sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
"node_modules/doctrine": {
"version": "2.1.0",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
@@ -2604,12 +3337,29 @@
"node": ">= 0.4"
}
},
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.321",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz",
+ "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.20.0",
"integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==",
@@ -2634,6 +3384,16 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/error-ex": {
"version": "1.3.4",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
@@ -2859,6 +3619,16 @@
"@esbuild/win32-x64": "0.27.2"
}
},
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
@@ -2871,6 +3641,39 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/escodegen": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/escodegen/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "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==",
@@ -3117,6 +3920,16 @@
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
}
},
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.4.26",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
+ "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "eslint": ">=8.40"
+ }
+ },
"node_modules/eslint-scope": {
"version": "8.4.0",
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
@@ -3162,6 +3975,20 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esquery": {
"version": "1.7.0",
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
@@ -3213,6 +4040,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.7.0"
+ }
+ },
"node_modules/execa": {
"version": "5.1.1",
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
@@ -3259,6 +4096,43 @@
"node": ">=4"
}
},
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extract-zip/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
@@ -3271,6 +4145,13 @@
"dev": true,
"license": "Apache-2.0"
},
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
@@ -3283,6 +4164,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
"node_modules/fdir": {
"version": "6.5.0",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
@@ -3458,6 +4349,26 @@
"node": ">= 0.4"
}
},
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
@@ -3536,6 +4447,21 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
+ "node_modules/get-uri": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz",
+ "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "basic-ftp": "^5.0.2",
+ "data-uri-to-buffer": "^6.0.2",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
@@ -3549,8 +4475,9 @@
}
},
"node_modules/globals": {
- "version": "14.0.0",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
+ "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3888,6 +4815,26 @@
"node": ">=8.0.0"
}
},
+ "node_modules/inquirer/node_modules/rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "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",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true,
+ "license": "0BSD"
+ },
"node_modules/internal-slot": {
"version": "1.1.0",
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
@@ -3902,6 +4849,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/ip-address": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
+ "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
@@ -4397,6 +5354,19 @@
}
}
},
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
@@ -4717,6 +5687,13 @@
"node": ">= 6"
}
},
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/mlly": {
"version": "1.8.0",
"integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
@@ -4785,6 +5762,23 @@
"ncp": "bin/ncp"
}
},
+ "node_modules/netmask": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+ "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.36",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
+ "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/normalize-package-data": {
"version": "3.0.3",
"integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
@@ -4935,6 +5929,16 @@
],
"license": "MIT"
},
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
"node_modules/onetime": {
"version": "5.1.2",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
@@ -5032,6 +6036,40 @@
"node": ">=6"
}
},
+ "node_modules/pac-proxy-agent": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+ "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "get-uri": "^6.0.1",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.6",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-resolver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "degenerator": "^5.0.0",
+ "netmask": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
@@ -5116,6 +6154,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
@@ -5281,26 +6326,84 @@
"react-is": "^17.0.1"
},
"engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/prop-types/node_modules/react-is": {
+ "version": "16.13.1",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/proxy-agent": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
+ "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.6",
+ "lru-cache": "^7.14.1",
+ "pac-proxy-agent": "^7.1.0",
+ "proxy-from-env": "^1.1.0",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
}
},
- "node_modules/prop-types": {
- "version": "15.8.1",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "node_modules/proxy-agent/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
}
},
- "node_modules/prop-types/node_modules/react-is": {
- "version": "16.13.1",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true,
"license": "MIT"
},
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
@@ -5318,6 +6421,47 @@
"node": ">=6"
}
},
+ "node_modules/puppeteer": {
+ "version": "24.40.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.40.0.tgz",
+ "integrity": "sha512-IxQbDq93XHVVLWHrAkFP7F7iHvb9o0mgfsSIMlhHb+JM+JjM1V4v4MNSQfcRWJopx9dsNOr9adYv0U5fm9BJBQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "2.13.0",
+ "chromium-bidi": "14.0.0",
+ "cosmiconfig": "^9.0.0",
+ "devtools-protocol": "0.0.1581282",
+ "puppeteer-core": "24.40.0",
+ "typed-query-selector": "^2.12.1"
+ },
+ "bin": {
+ "puppeteer": "lib/cjs/puppeteer/node/cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/puppeteer-core": {
+ "version": "24.40.0",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.40.0.tgz",
+ "integrity": "sha512-MWL3XbUCfVgGR0gRsidzT6oKJT2QydPLhMITU6HoVWiiv4gkb6gJi3pcdAa8q4HwjBTbqISOWVP4aJiiyUJvag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "2.13.0",
+ "chromium-bidi": "14.0.0",
+ "debug": "^4.4.3",
+ "devtools-protocol": "0.0.1581282",
+ "typed-query-selector": "^2.12.1",
+ "webdriver-bidi-protocol": "0.4.1",
+ "ws": "^8.19.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/quick-lru": {
"version": "4.0.1",
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
@@ -5359,6 +6503,16 @@
"license": "MIT",
"peer": true
},
+ "node_modules/react-refresh": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/read-pkg": {
"version": "5.2.0",
"integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
@@ -5576,6 +6730,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/require-from-string": {
"version": "2.0.2",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
@@ -5687,15 +6851,12 @@
}
},
"node_modules/rxjs": {
- "version": "6.6.7",
- "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
- "dev": true,
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"dependencies": {
- "tslib": "^1.9.0"
- },
- "engines": {
- "npm": ">=2.0.0"
+ "tslib": "^2.1.0"
}
},
"node_modules/safe-array-concat": {
@@ -5937,6 +7098,47 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.7",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
+ "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^10.0.1",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/source-map": {
"version": "0.7.6",
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
@@ -6012,6 +7214,18 @@
"node": ">= 0.4"
}
},
+ "node_modules/streamx": {
+ "version": "2.25.0",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
+ "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "events-universal": "^1.0.0",
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
@@ -6244,6 +7458,84 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/tar-fs": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz",
+ "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0",
+ "tar-stream": "^3.1.5"
+ },
+ "optionalDependencies": {
+ "bare-fs": "^4.0.1",
+ "bare-path": "^3.0.0"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz",
+ "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "bare-fs": "^4.5.5",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/tar-stream/node_modules/b4a": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
+ "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/teex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "streamx": "^2.12.5"
+ }
+ },
+ "node_modules/text-decoder": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
+ "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
+ "node_modules/text-decoder/node_modules/b4a": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
+ "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
"node_modules/thenify": {
"version": "3.3.1",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
@@ -6421,9 +7713,9 @@
"license": "Apache-2.0"
},
"node_modules/tslib": {
- "version": "1.14.1",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true,
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/tsup": {
@@ -6478,6 +7770,26 @@
}
}
},
+ "node_modules/tsx": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
+ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.27.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
@@ -6576,6 +7888,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typed-query-selector": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz",
+ "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/typescript": {
"version": "5.9.3",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
@@ -6650,6 +7969,44 @@
"node": ">=20.18.1"
}
},
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
@@ -6841,6 +8198,13 @@
"node": ">=18"
}
},
+ "node_modules/webdriver-bidi-protocol": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz",
+ "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/webidl-conversions": {
"version": "8.0.1",
"integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==",
@@ -6998,6 +8362,47 @@
"node": ">=0.10.0"
}
},
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "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",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/write-file-atomic": {
"version": "6.0.0",
"integrity": "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==",
@@ -7023,6 +8428,28 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/ws": {
+ "version": "8.19.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
+ "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/xml-name-validator": {
"version": "5.0.0",
"integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
@@ -7038,12 +8465,41 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/yallist": {
"version": "4.0.0",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true,
"license": "ISC"
},
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/yargs-parser": {
"version": "20.2.9",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
@@ -7053,6 +8509,27 @@
"node": ">=10"
}
},
+ "node_modules/yargs/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
@@ -7064,6 +8541,15 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
}
}
diff --git a/renderers/react/package.json b/renderers/react/package.json
index b36dfa188..c156c76c4 100644
--- a/renderers/react/package.json
+++ b/renderers/react/package.json
@@ -27,6 +27,16 @@
"default": "./dist/v0_8/index.cjs"
}
},
+ "./v0_9": {
+ "import": {
+ "types": "./dist/v0_9/index.d.ts",
+ "default": "./dist/v0_9/index.js"
+ },
+ "require": {
+ "types": "./dist/v0_9/index.d.cts",
+ "default": "./dist/v0_9/index.cjs"
+ }
+ },
"./styles": {
"import": {
"types": "./dist/styles/index.d.ts",
@@ -55,7 +65,10 @@
"lint:fix": "eslint src --fix",
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
- "clean": "rm -rf dist"
+ "clean": "rm -rf dist",
+ "demo": "cd a2ui_explorer && vite",
+ "build:demo": "cd a2ui_explorer && tsc -b && vite build",
+ "test:demo": "cd a2ui_explorer && vitest run src"
},
"dependencies": {
"@a2ui/web_core": "file:../web_core",
@@ -64,27 +77,36 @@
},
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
- "react-dom": "^18.0.0 || ^19.0.0"
+ "react-dom": "^18.0.0 || ^19.0.0",
+ "rxjs": "^7.8.1",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"@testing-library/jest-dom": "^6.6.0",
"@testing-library/react": "^16.0.0",
"@types/markdown-it": "^14.1.0",
+ "@types/node": "^24.10.1",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
+ "@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-react": "^7.37.0",
"eslint-plugin-react-hooks": "^5.0.0",
+ "eslint-plugin-react-refresh": "^0.4.24",
+ "globals": "^16.5.0",
"gts": "^7.0.0",
"jsdom": "^28.0.0",
"prettier": "^3.4.0",
+ "puppeteer": "^24.39.0",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"tsup": "^8.0.0",
+ "tsx": "^4.21.0",
"typescript": "^5.8.0",
"typescript-eslint": "^8.0.0",
+ "vite": "^7.3.1",
"vitest": "^4.0.18"
},
"keywords": [
diff --git a/renderers/react/src/v0_9/A2uiSurface.tsx b/renderers/react/src/v0_9/A2uiSurface.tsx
new file mode 100644
index 000000000..125593371
--- /dev/null
+++ b/renderers/react/src/v0_9/A2uiSurface.tsx
@@ -0,0 +1,132 @@
+/**
+ * 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 React, {useSyncExternalStore, memo, useMemo, useCallback} from 'react';
+import {type SurfaceModel, ComponentContext, type ComponentModel} from '@a2ui/web_core/v0_9';
+import type {ReactComponentImplementation} from './adapter';
+
+const ResolvedChild = memo(
+ ({
+ surface,
+ id,
+ basePath,
+ compImpl,
+ componentModel,
+ }: {
+ surface: SurfaceModel;
+ id: string;
+ basePath: string;
+ componentModel: ComponentModel;
+ compImpl: ReactComponentImplementation;
+ }) => {
+ const ComponentToRender = compImpl.render;
+
+ // Create context. Recreate if the componentModel instance changes (e.g. type change recreation).
+ const context = useMemo(
+ () => new ComponentContext(surface, id, 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]
+ );
+
+ const buildChild = useCallback(
+ (childId: string, specificPath?: string) => {
+ const path = specificPath || context.dataContext.path;
+ return (
+
+ );
+ },
+ [surface, context.dataContext.path]
+ );
+
+ return ;
+ }
+);
+ResolvedChild.displayName = 'ResolvedChild';
+
+export const DeferredChild: React.FC<{
+ surface: SurfaceModel;
+ id: string;
+ basePath: string;
+}> = memo(({surface, id, basePath}) => {
+ // 1. Subscribe specifically to this component's existence
+ const store = useMemo(() => {
+ let version = 0;
+ return {
+ subscribe: (cb: () => void) => {
+ const unsub1 = surface.componentsModel.onCreated.subscribe((comp) => {
+ if (comp.id === id) {
+ version++;
+ cb();
+ }
+ });
+ const unsub2 = surface.componentsModel.onDeleted.subscribe((delId) => {
+ if (delId === id) {
+ version++;
+ cb();
+ }
+ });
+ return () => {
+ unsub1.unsubscribe();
+ unsub2.unsubscribe();
+ };
+ },
+ getSnapshot: () => {
+ const comp = surface.componentsModel.get(id);
+ // We use instance identity + version as the snapshot to ensure
+ // type replacements (e.g. Button -> Text) trigger a re-render.
+ return comp ? `${comp.type}-${version}` : `missing-${version}`;
+ },
+ };
+ }, [surface, id]);
+
+ useSyncExternalStore(store.subscribe, store.getSnapshot);
+
+ const componentModel = surface.componentsModel.get(id);
+
+ if (!componentModel) {
+ return [Loading {id}...]
;
+ }
+
+ const compImpl = surface.catalog.components.get(componentModel.type);
+
+ if (!compImpl) {
+ return Unknown component: {componentModel.type}
;
+ }
+
+ return (
+
+ );
+});
+DeferredChild.displayName = 'DeferredChild';
+
+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
new file mode 100644
index 000000000..969235b25
--- /dev/null
+++ b/renderers/react/src/v0_9/adapter.tsx
@@ -0,0 +1,114 @@
+/**
+ * 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 React, {useRef, useSyncExternalStore, useCallback, memo, useEffect} from 'react';
+import {type z} from 'zod';
+import {type ComponentContext, GenericBinder} from '@a2ui/web_core/v0_9';
+import type {ComponentApi, ResolveA2uiProps} from '@a2ui/web_core/v0_9';
+
+export interface ReactComponentImplementation extends ComponentApi {
+ /** The framework-specific rendering wrapper. */
+ render: React.FC<{
+ context: ComponentContext;
+ buildChild: (id: string, basePath?: string) => React.ReactNode;
+ }>;
+}
+
+export type ReactA2uiComponentProps = {
+ props: T;
+ buildChild: (id: string, basePath?: string) => React.ReactNode;
+ context: ComponentContext;
+};
+
+// --- Component Factories ---
+
+/**
+ * Creates a React component implementation using the deep generic binder.
+ */
+export function createReactComponent(
+ api: {name: string; schema: Schema},
+ RenderComponent: React.FC>>>
+): ReactComponentImplementation {
+ type Props = ResolveA2uiProps>;
+
+ const MemoizedRender = memo(RenderComponent, (prev, next) => {
+ if (prev.props !== next.props) return false;
+ if (prev.context.componentModel.id !== next.context.componentModel.id) return false;
+ if (prev.context.dataContext.path !== next.context.dataContext.path) return false;
+ return true;
+ });
+
+ const ReactWrapper: React.FC<{
+ context: ComponentContext;
+ buildChild: (id: string, basePath?: string) => React.ReactNode;
+ }> = ({context, buildChild}) => {
+ 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.dispose();
+ bindingRef.current = new GenericBinder(context, api.schema);
+ }
+ const binding = bindingRef.current;
+
+ const subscribe = useCallback(
+ (callback: () => void) => {
+ const sub = binding.subscribe(callback);
+ return () => sub.unsubscribe();
+ },
+ [binding]
+ );
+
+ const getSnapshot = useCallback(() => binding.snapshot, [binding]);
+ const props = useSyncExternalStore(subscribe, getSnapshot);
+
+ // Prevent DataModel subscription leaks on unmount
+ useEffect(() => {
+ return () => binding.dispose();
+ }, [binding]);
+
+ return (
+
+ );
+ };
+
+ return {
+ name: api.name,
+ schema: api.schema,
+ render: ReactWrapper,
+ };
+}
+
+/**
+ * Creates a React component implementation that manages its own context bindings (no generic binder).
+ */
+export function createBinderlessComponent(
+ api: ComponentApi,
+ RenderComponent: React.FC<{
+ context: ComponentContext;
+ buildChild: (id: string, basePath?: string) => React.ReactNode;
+ }>
+): ReactComponentImplementation {
+ return {
+ name: api.name,
+ schema: api.schema,
+ render: RenderComponent,
+ };
+}
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/Button.tsx b/renderers/react/src/v0_9/catalog/minimal/components/Button.tsx
new file mode 100644
index 000000000..f01d81d79
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/Button.tsx
@@ -0,0 +1,48 @@
+/**
+ * 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 React from 'react';
+import {createReactComponent} from '../../../adapter';
+import {z} from 'zod';
+import {CommonSchemas} from '@a2ui/web_core/v0_9';
+
+export const ButtonSchema = z.object({
+ child: CommonSchemas.ComponentId,
+ action: CommonSchemas.Action,
+ variant: z.enum(['primary', 'borderless']).optional(),
+});
+
+export const ButtonApiDef = {
+ name: 'Button',
+ schema: ButtonSchema,
+};
+
+export const Button = createReactComponent(ButtonApiDef, ({props, buildChild}) => {
+ const style: React.CSSProperties = {
+ padding: '8px 16px',
+ cursor: 'pointer',
+ border: props.variant === 'borderless' ? 'none' : '1px solid #ccc',
+ backgroundColor: props.variant === 'primary' ? '#007bff' : 'transparent',
+ color: props.variant === 'primary' ? '#fff' : 'inherit',
+ borderRadius: '4px',
+ };
+
+ return (
+
+ {props.child ? buildChild(props.child) : null}
+
+ );
+});
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/ChildList.tsx b/renderers/react/src/v0_9/catalog/minimal/components/ChildList.tsx
new file mode 100644
index 000000000..066433355
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/ChildList.tsx
@@ -0,0 +1,47 @@
+/**
+ * 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 React from 'react';
+
+export const ChildList: React.FC<{
+ childList: unknown;
+ buildChild: (id: string, basePath?: string) => React.ReactNode;
+}> = ({childList, buildChild}) => {
+ if (Array.isArray(childList)) {
+ return (
+ <>
+ {childList.map((item: unknown, i: number) => {
+ // The new binder outputs objects like { id: string, basePath: string } for arrays of structural nodes
+ if (item && typeof item === 'object' && 'id' in item) {
+ const node = item as {id: string; basePath?: string};
+ return (
+
+ {buildChild(node.id, node.basePath)}
+
+ );
+ }
+ // Fallback for static string lists
+ if (typeof item === 'string') {
+ return {buildChild(item)} ;
+ }
+ return null;
+ })}
+ >
+ );
+ }
+
+ return null;
+};
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/Column.tsx b/renderers/react/src/v0_9/catalog/minimal/components/Column.tsx
new file mode 100644
index 000000000..b137f372c
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/Column.tsx
@@ -0,0 +1,85 @@
+/**
+ * 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 {createReactComponent} from '../../../adapter';
+import {z} from 'zod';
+import {CommonSchemas} from '@a2ui/web_core/v0_9';
+import {ChildList} from './ChildList';
+
+export const ColumnSchema = z.object({
+ children: CommonSchemas.ChildList,
+ justify: z
+ .enum(['start', 'center', 'end', 'spaceBetween', 'spaceAround', 'spaceEvenly', 'stretch'])
+ .optional(),
+ align: z.enum(['center', 'end', 'start', 'stretch']).optional(),
+});
+
+const mapJustify = (j?: string) => {
+ switch (j) {
+ case 'center':
+ return 'center';
+ case 'end':
+ return 'flex-end';
+ case 'spaceAround':
+ return 'space-around';
+ case 'spaceBetween':
+ return 'space-between';
+ case 'spaceEvenly':
+ return 'space-evenly';
+ case 'start':
+ return 'flex-start';
+ case 'stretch':
+ return 'stretch';
+ default:
+ return 'flex-start';
+ }
+};
+
+const mapAlign = (a?: string) => {
+ switch (a) {
+ case 'start':
+ return 'flex-start';
+ case 'center':
+ return 'center';
+ case 'end':
+ return 'flex-end';
+ case 'stretch':
+ return 'stretch';
+ default:
+ return 'stretch';
+ }
+};
+
+export const ColumnApiDef = {
+ name: 'Column',
+ schema: ColumnSchema,
+};
+
+export const Column = createReactComponent(ColumnApiDef, ({props, buildChild}) => {
+ return (
+
+
+
+ );
+});
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/Row.tsx b/renderers/react/src/v0_9/catalog/minimal/components/Row.tsx
new file mode 100644
index 000000000..7e8cd9bad
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/Row.tsx
@@ -0,0 +1,84 @@
+/**
+ * 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 {createReactComponent} from '../../../adapter';
+import {z} from 'zod';
+import {CommonSchemas} from '@a2ui/web_core/v0_9';
+import {ChildList} from './ChildList';
+
+export const RowSchema = z.object({
+ children: CommonSchemas.ChildList,
+ justify: z
+ .enum(['center', 'end', 'spaceAround', 'spaceBetween', 'spaceEvenly', 'start', 'stretch'])
+ .optional(),
+ align: z.enum(['start', 'center', 'end', 'stretch']).optional(),
+});
+
+const mapJustify = (j?: string) => {
+ switch (j) {
+ case 'center':
+ return 'center';
+ case 'end':
+ return 'flex-end';
+ case 'spaceAround':
+ return 'space-around';
+ case 'spaceBetween':
+ return 'space-between';
+ case 'spaceEvenly':
+ return 'space-evenly';
+ case 'start':
+ return 'flex-start';
+ case 'stretch':
+ return 'stretch';
+ default:
+ return 'flex-start';
+ }
+};
+
+const mapAlign = (a?: string) => {
+ switch (a) {
+ case 'start':
+ return 'flex-start';
+ case 'center':
+ return 'center';
+ case 'end':
+ return 'flex-end';
+ case 'stretch':
+ return 'stretch';
+ default:
+ return 'stretch';
+ }
+};
+
+export const RowApiDef = {
+ name: 'Row',
+ schema: RowSchema,
+};
+
+export const Row = createReactComponent(RowApiDef, ({props, buildChild}) => {
+ return (
+
+
+
+ );
+});
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx b/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx
new file mode 100644
index 000000000..b36c43221
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/Text.tsx
@@ -0,0 +1,50 @@
+/**
+ * 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 {createReactComponent} from '../../../adapter';
+import {z} from 'zod';
+import {CommonSchemas} from '@a2ui/web_core/v0_9';
+
+export const TextSchema = z.object({
+ text: CommonSchemas.DynamicString,
+ variant: z.enum(['h1', 'h2', 'h3', 'h4', 'h5', 'caption', 'body']).optional(),
+});
+
+export const TextApiDef = {
+ name: 'Text',
+ schema: TextSchema,
+};
+
+export const Text = createReactComponent(TextApiDef, ({props}) => {
+ const text = props.text ?? '';
+ switch (props.variant) {
+ case 'h1':
+ return {text} ;
+ case 'h2':
+ return {text} ;
+ case 'h3':
+ return {text} ;
+ case 'h4':
+ return {text} ;
+ case 'h5':
+ return {text} ;
+ case 'caption':
+ return {text} ;
+ case 'body':
+ default:
+ return {text} ;
+ }
+});
diff --git a/renderers/react/src/v0_9/catalog/minimal/components/TextField.tsx b/renderers/react/src/v0_9/catalog/minimal/components/TextField.tsx
new file mode 100644
index 000000000..f8f06ad90
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/components/TextField.tsx
@@ -0,0 +1,69 @@
+/**
+ * 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 React from 'react';
+import {createReactComponent} from '../../../adapter';
+import {z} from 'zod';
+import {CommonSchemas} from '@a2ui/web_core/v0_9';
+
+export const TextFieldSchema = z.object({
+ label: CommonSchemas.DynamicString,
+ value: CommonSchemas.DynamicString,
+ variant: z.enum(['longText', 'number', 'shortText', 'obscured']).optional(),
+ validationRegexp: z.string().optional(),
+});
+
+export const TextFieldApiDef = {
+ name: 'TextField',
+ schema: TextFieldSchema,
+};
+
+export const TextField = createReactComponent(TextFieldApiDef, ({props, context}) => {
+ const onChange = (e: React.ChangeEvent) => {
+ if (props.setValue) {
+ props.setValue(e.target.value);
+ }
+ };
+
+ const isLong = props.variant === 'longText';
+ const type =
+ props.variant === 'number' ? 'number' : props.variant === 'obscured' ? 'password' : 'text';
+
+ const style: React.CSSProperties = {
+ padding: '8px',
+ width: '100%',
+ border: '1px solid #ccc',
+ borderRadius: '4px',
+ boxSizing: 'border-box',
+ };
+
+ const id = `textfield-${context.componentModel.id}`;
+
+ return (
+
+ {props.label && (
+
+ {props.label}
+
+ )}
+ {isLong ? (
+
+ ) : (
+
+ )}
+
+ );
+});
diff --git a/renderers/react/src/v0_9/catalog/minimal/index.ts b/renderers/react/src/v0_9/catalog/minimal/index.ts
new file mode 100644
index 000000000..74f8a8f57
--- /dev/null
+++ b/renderers/react/src/v0_9/catalog/minimal/index.ts
@@ -0,0 +1,49 @@
+/**
+ * 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 {Catalog, createFunctionImplementation} from '@a2ui/web_core/v0_9';
+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(
+ 'https://a2ui.org/specification/v0_9/catalogs/minimal/minimal_catalog.json',
+ minimalComponents,
+ [
+ createFunctionImplementation(
+ {
+ name: 'capitalize',
+ returnType: 'string',
+ schema: z.object({
+ value: z.unknown(),
+ }),
+ },
+ (args) => {
+ const val = args.value;
+ if (typeof val === 'string') {
+ return val.toUpperCase();
+ }
+ return val as string;
+ }
+ ),
+ ]
+);
diff --git a/renderers/react/src/v0_9/index.ts b/renderers/react/src/v0_9/index.ts
new file mode 100644
index 000000000..266217d34
--- /dev/null
+++ b/renderers/react/src/v0_9/index.ts
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+export * from './A2uiSurface';
+export * from './adapter';
+export * from './catalog/minimal';
+// Minimal catalog components are exported from here for backwards compatibility or specific use.
+export {Button as MinimalButton} from './catalog/minimal/components/Button';
+export {Column as MinimalColumn} from './catalog/minimal/components/Column';
+export {Row as MinimalRow} from './catalog/minimal/components/Row';
+export {Text as MinimalText} from './catalog/minimal/components/Text';
+export {TextField as MinimalTextField} from './catalog/minimal/components/TextField';
+export * from './catalog/minimal/components/ChildList';
diff --git a/renderers/react/tests/v0_9/adapter.test.tsx b/renderers/react/tests/v0_9/adapter.test.tsx
new file mode 100644
index 000000000..bd9ef03a1
--- /dev/null
+++ b/renderers/react/tests/v0_9/adapter.test.tsx
@@ -0,0 +1,174 @@
+/**
+ * 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 { 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';
+
+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' });
+ surface.componentsModel.addComponent(compModel);
+
+ const context = new ComponentContext(surface, 'c1', '/');
+
+ const TestApiDef = {
+ name: 'TestComp',
+ schema: z.object({
+ text: CommonSchemas.DynamicString,
+ child: CommonSchemas.ComponentId
+ })
+ };
+
+ const TestComponent = createReactComponent(
+ TestApiDef,
+ ({ props, buildChild }) => {
+ return
+ {props.text}
+ {props.child && buildChild(props.child)}
+
;
+ }
+ );
+
+ const buildChild = vi.fn().mockImplementation((id) => Child
);
+
+ render( );
+
+ expect(screen.getByText('Hello World')).toBeDefined();
+ expect(screen.getByTestId('child1')).toBeDefined();
+ });
+
+ it('should react to data model changes', async () => {
+ const surface = new SurfaceModel('test-surface', mockCatalog);
+ 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 TestApiDef = {
+ name: 'TestComp',
+ schema: z.object({
+ text: CommonSchemas.DynamicString
+ })
+ };
+
+ const TestComponent = createReactComponent(
+ TestApiDef,
+ ({ props }) => {
+ return {props.text}
;
+ }
+ );
+
+ const { getByTestId } = render( null} />);
+
+ expect(getByTestId('msg').textContent).toBe('Hello Reactive');
+
+ // Update data model
+ await act(async () => {
+ surface.dataModel.set('/greeting', 'Updated Greeting');
+ });
+
+ expect(getByTestId('msg').textContent).toBe('Updated Greeting');
+ });
+
+ it('should clean up listeners on unmount', () => {
+ const surface = new SurfaceModel('test-surface', mockCatalog);
+ const compModel = new ComponentModel('c1', 'TestComp', { text: { path: '/greeting' } });
+ surface.componentsModel.addComponent(compModel);
+
+ const context = new ComponentContext(surface, 'c1', '/');
+
+ const unsubscribeSpy = vi.fn();
+ const spyAddListener = vi.spyOn(context.dataContext, 'subscribeDynamicValue').mockReturnValue({
+ value: 'initial',
+ unsubscribe: unsubscribeSpy,
+ });
+
+ const TestApiDef = {
+ name: 'TestComp',
+ schema: z.object({
+ text: CommonSchemas.DynamicString
+ })
+ };
+
+ const TestComponent = createReactComponent(
+ TestApiDef,
+ ({ props }) => {
+ return {props.text}
;
+ }
+ );
+
+ 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 }) };
+
+ let parentRenderCount = 0;
+
+ const TestParent = createReactComponent(ParentApiDef, ({ props, buildChild }) => {
+ parentRenderCount++;
+ return {props.child && buildChild(props.child)}
;
+ });
+
+ const TestChild = createReactComponent(ChildApiDef, ({ props }) => (
+ {props.text}
+ ));
+
+ const testCatalog = new Catalog('test', [TestParent, TestChild], []);
+ const surface = new SurfaceModel('test-surface', testCatalog);
+
+ // 1. Initial State: Parent component exists, but its child is missing from the surface.
+ const parentModel = new ComponentModel('root', 'TestParent', { child: 'child1' });
+ surface.componentsModel.addComponent(parentModel);
+
+ 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' }));
+ });
+
+ // 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
new file mode 100644
index 000000000..58150876c
--- /dev/null
+++ b/renderers/react/tests/v0_9/components.test.tsx
@@ -0,0 +1,168 @@
+/**
+ * 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 { 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';
+
+const mockCatalog = new Catalog('test', [], []);
+
+function createContext(type: string, properties: any) {
+ const surface = new SurfaceModel('test-surface', mockCatalog);
+ const compModel = new ComponentModel('test-id', type, properties);
+ surface.componentsModel.addComponent(compModel);
+ return new ComponentContext(surface, 'test-id', '/');
+}
+
+describe('Text', () => {
+ it('renders text and variant correctly', () => {
+ 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 span = container.querySelector('span');
+ expect(span).not.toBeNull();
+ expect(span?.textContent).toBe('Hello');
+ });
+});
+
+describe('Button', () => {
+ it('renders and dispatches action', () => {
+ const ctx = createContext('Button', {
+ child: 'btn-child',
+ variant: 'primary',
+ action: { event: { name: 'test_action' } }
+ });
+
+ const spy = vi.spyOn(ctx, 'dispatchAction').mockResolvedValue();
+
+ const buildChild = vi.fn().mockImplementation((id) => {id} );
+
+ render( );
+
+ 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' } });
+ });
+});
+
+describe('Row', () => {
+ it('renders children with correct flex styles', () => {
+ const ctx = createContext('Row', {
+ children: ['c1', 'c2'],
+ justify: 'spaceBetween',
+ align: 'center'
+ });
+
+ const buildChild = vi.fn().mockImplementation((id) => {id}
);
+
+ const { container } = render( );
+ const rowDiv = container.firstChild as HTMLElement;
+ expect(rowDiv.style.display).toBe('flex');
+ expect(rowDiv.style.flexDirection).toBe('row');
+ expect(rowDiv.style.justifyContent).toBe('space-between');
+ expect(rowDiv.style.alignItems).toBe('center');
+
+ expect(screen.getByTestId('c1')).toBeDefined();
+ expect(screen.getByTestId('c2')).toBeDefined();
+ });
+});
+
+describe('Column', () => {
+ it('renders children with correct flex styles', () => {
+ const ctx = createContext('Column', {
+ children: ['c1'],
+ justify: 'center',
+ align: 'start'
+ });
+
+ const buildChild = vi.fn().mockImplementation((id) => {id}
);
+
+ const { container } = render( );
+ const colDiv = container.firstChild as HTMLElement;
+ expect(colDiv.style.display).toBe('flex');
+ expect(colDiv.style.flexDirection).toBe('column');
+ expect(colDiv.style.justifyContent).toBe('center');
+ expect(colDiv.style.alignItems).toBe('flex-start');
+
+ expect(screen.getByTestId('c1')).toBeDefined();
+ });
+});
+
+describe('TextField', () => {
+ it('renders label and text input', () => {
+ const ctx = createContext('TextField', {
+ label: 'Username',
+ value: 'alice',
+ variant: 'shortText'
+ });
+
+ const { container } = render( null} />);
+ const label = container.querySelector('label');
+ expect(label?.textContent).toBe('Username');
+
+ const input = container.querySelector('input');
+ expect(input?.type).toBe('text');
+ expect(input?.value).toBe('alice');
+ });
+
+ it('renders textarea for longText', () => {
+ const ctx = createContext('TextField', {
+ label: 'Comments',
+ value: 'lots of text',
+ variant: 'longText'
+ });
+
+ const { container } = render( null} />);
+ const textarea = container.querySelector('textarea');
+ expect(textarea).not.toBeNull();
+ expect(textarea?.value).toBe('lots of text');
+ });
+
+ it('updates data model on change', () => {
+ const ctx = createContext('TextField', {
+ label: 'Username',
+ value: { path: '/user' }
+ });
+
+ const spySet = vi.spyOn(ctx.dataContext, 'set');
+
+ const { container } = render( null} />);
+ const input = container.querySelector('input');
+
+ fireEvent.change(input!, { target: { value: 'bob' } });
+
+ expect(spySet).toHaveBeenCalledWith('/user', 'bob');
+ });
+});
diff --git a/renderers/react/tsup.config.ts b/renderers/react/tsup.config.ts
index 5768516ce..26b5f1437 100644
--- a/renderers/react/tsup.config.ts
+++ b/renderers/react/tsup.config.ts
@@ -22,6 +22,7 @@ export default defineConfig([
entry: {
index: 'src/index.ts',
'v0_8/index': 'src/v0_8/index.ts',
+ 'v0_9/index': 'src/v0_9/index.ts',
},
format: ['esm', 'cjs'],
dts: true,