From 2bab9d51139b64524f16569f350e779d4827bf55 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 29 Jun 2026 17:14:21 +0100 Subject: [PATCH 1/5] add and configure react-compiler --- package.json | 2 + packages/react/package.json | 2 + packages/react/vite.config.ts | 3 +- packages/vis/package.json | 2 + packages/vis/vite.config.demo.ts | 11 ++-- packages/vis/vite.config.ts | 1 + pnpm-lock.yaml | 100 +++++++++++++++++++++---------- pnpm-workspace.yaml | 2 + vite.config.base.ts | 21 ++++++- 9 files changed, 105 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index ac06f3ad..27796f87 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,9 @@ "@biomejs/biome": "^1.9.4", "@changesets/changelog-github": "^0.7.0", "@changesets/cli": "^2.31.0", + "@rolldown/plugin-babel": "catalog:", "@vitejs/plugin-react": "catalog:", + "babel-plugin-react-compiler": "catalog:", "@zarrita/storage": "catalog:", "typescript": "catalog:", "vite": "catalog:", diff --git a/packages/react/package.json b/packages/react/package.json index fdff2a4a..f6abf32f 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,7 +37,9 @@ "@types/node": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@rolldown/plugin-babel": "catalog:", "@vitejs/plugin-react": "catalog:", + "babel-plugin-react-compiler": "catalog:", "jsdom": "catalog:", "typescript": "catalog:", "vite": "catalog:", diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts index d499c26f..6c248487 100644 --- a/packages/react/vite.config.ts +++ b/packages/react/vite.config.ts @@ -1,6 +1,6 @@ import { fileURLToPath } from 'node:url'; -import { defineViteConfig } from '../../vite.config.base'; import { mergeConfig } from 'vite'; +import { defineViteConfig } from '../../vite.config.base'; const pkgRoot = fileURLToPath(new URL('.', import.meta.url)); @@ -8,6 +8,7 @@ const baseConfig = defineViteConfig({ pkgRoot, libName: 'SpatialDataReact', external: ['@spatialdata/core'], + reactCompiler: true, }); export default mergeConfig(baseConfig, { diff --git a/packages/vis/package.json b/packages/vis/package.json index 44f1769c..4ae88ed5 100644 --- a/packages/vis/package.json +++ b/packages/vis/package.json @@ -58,7 +58,9 @@ "@types/node": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@rolldown/plugin-babel": "catalog:", "@vitejs/plugin-react": "catalog:", + "babel-plugin-react-compiler": "catalog:", "jsdom": "catalog:", "typescript": "catalog:", "vite": "catalog:", diff --git a/packages/vis/vite.config.demo.ts b/packages/vis/vite.config.demo.ts index 6c5db8e9..77894c06 100644 --- a/packages/vis/vite.config.demo.ts +++ b/packages/vis/vite.config.demo.ts @@ -1,9 +1,10 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import path from 'node:path'; import { createRequire } from 'node:module'; -import { createWorkspaceSourceAliases } from '../../vite.config.base'; +import path from 'node:path'; +import babel from '@rolldown/plugin-babel'; +import react, { reactCompilerPreset } from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; import { fixtureServerOrigin } from '../../scripts/fixture-server-port.mjs'; +import { createWorkspaceSourceAliases } from '../../vite.config.base'; // https://vitejs.dev/config/ const workspaceRoot = path.resolve(__dirname, '../..'); @@ -13,7 +14,7 @@ const reactDomRoot = path.dirname(require.resolve('react-dom/package.json')); export default defineConfig({ root: path.resolve(__dirname, 'demo'), - plugins: [react()], + plugins: [react(), babel({ presets: [reactCompilerPreset()] })], resolve: { alias: [ ...createWorkspaceSourceAliases(workspaceRoot), diff --git a/packages/vis/vite.config.ts b/packages/vis/vite.config.ts index f79701f2..fabffad1 100644 --- a/packages/vis/vite.config.ts +++ b/packages/vis/vite.config.ts @@ -23,6 +23,7 @@ const baseConfig = defineViteConfig({ 'zarrita', /^zarrextra(?:\/.*)?$/, ], + reactCompiler: true, }); export default mergeConfig(baseConfig, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4ab3602..21e7b683 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,9 @@ catalogs: '@math.gl/core': specifier: ^4.1.0 version: 4.1.0 + '@rolldown/plugin-babel': + specifier: ^0.2.3 + version: 0.2.3 '@types/node': specifier: ^22.10.5 version: 22.18.8 @@ -45,6 +48,9 @@ catalogs: apache-arrow: specifier: ^17.0.0 version: 17.0.0 + babel-plugin-react-compiler: + specifier: ^1.0.0 + version: 1.0.0 deck.gl: specifier: ~9.3.5 version: 9.3.5 @@ -92,12 +98,18 @@ importers: '@changesets/cli': specifier: ^2.31.0 version: 2.31.0(@types/node@22.18.8) + '@rolldown/plugin-babel': + specifier: 'catalog:' + version: 0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) '@zarrita/storage': specifier: 'catalog:' version: 0.2.0 + babel-plugin-react-compiler: + specifier: 'catalog:' + version: 1.0.0 typescript: specifier: 'catalog:' version: 5.9.3 @@ -195,7 +207,7 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) jsdom: specifier: 'catalog:' version: 27.4.0 @@ -319,6 +331,9 @@ importers: specifier: 'catalog:' version: 0.7.1 devDependencies: + '@rolldown/plugin-babel': + specifier: 'catalog:' + version: 0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) '@types/node': specifier: 'catalog:' version: 22.18.8 @@ -330,7 +345,10 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + babel-plugin-react-compiler: + specifier: 'catalog:' + version: 1.0.0 jsdom: specifier: 'catalog:' version: 27.4.0 @@ -413,6 +431,9 @@ importers: '@cornerstonejs/codec-openjpeg': specifier: ^1.3.0 version: 1.3.0 + '@rolldown/plugin-babel': + specifier: 'catalog:' + version: 0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) '@types/node': specifier: 'catalog:' version: 22.18.8 @@ -424,10 +445,13 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: 'catalog:' - version: 6.0.1(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) '@vivjs/constants': specifier: 'catalog:' version: 0.22.0 + babel-plugin-react-compiler: + specifier: 'catalog:' + version: 1.0.0 jsdom: specifier: 'catalog:' version: 27.4.0 @@ -1924,21 +1948,12 @@ packages: '@fideus-labs/worker-pool@1.0.0': resolution: {integrity: sha512-Mwx8fFKKpTUcEtR7w45MQJ/RnZFUPBtefEvGTZGlZMAVSfD7W61rpB8ZdgS4V0CXfppwcb90BF7F/aANWvupnA==} - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - '@floating-ui/dom@1.7.6': resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} @@ -2400,6 +2415,23 @@ packages: cpu: [x64] os: [win32] + '@rolldown/plugin-babel@0.2.3': + resolution: {integrity: sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==} + engines: {node: '>=22.12.0 || ^24.0.0'} + peerDependencies: + '@babel/core': ^7.29.0 || ^8.0.0-rc.1 + '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1 + '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1 + rolldown: ^1.0.0-rc.5 + vite: ^8.0.0 + peerDependenciesMeta: + '@babel/plugin-transform-runtime': + optional: true + '@babel/runtime': + optional: true + vite: + optional: true + '@rolldown/pluginutils@1.0.0-rc.15': resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} @@ -3505,6 +3537,9 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-react-compiler@1.0.0: + resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -10407,11 +10442,11 @@ snapshots: '@arcgis/lumina': 4.34.9(lit@3.3.1) '@arcgis/toolkit': 4.34.9 '@esri/calcite-ui-icons': 4.3.0 - '@floating-ui/dom': 1.7.4 - '@floating-ui/utils': 0.2.10 + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.11 '@types/sortablejs': 1.15.9 color: 5.0.3 - composed-offset-position: 0.0.6(@floating-ui/utils@0.2.10) + composed-offset-position: 0.0.6(@floating-ui/utils@0.2.11) es-toolkit: 1.42.0 focus-trap: 7.6.6 interactjs: 1.10.27 @@ -10435,26 +10470,15 @@ snapshots: '@fideus-labs/worker-pool@1.0.0': optional: true - '@floating-ui/core@1.7.3': - dependencies: - '@floating-ui/utils': 0.2.10 - '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.4': - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - '@floating-ui/dom@1.7.6': dependencies: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - '@floating-ui/utils@0.2.10': {} - '@floating-ui/utils@0.2.11': {} '@foliojs-fork/fontkit@1.9.2': @@ -11060,6 +11084,15 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': optional: true + '@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0))': + dependencies: + '@babel/core': 7.28.4 + picomatch: 4.0.4 + rolldown: 1.0.0-rc.15 + optionalDependencies: + '@babel/runtime': 7.28.4 + vite: 8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0) + '@rolldown/pluginutils@1.0.0-rc.15': {} '@rolldown/pluginutils@1.0.0-rc.7': {} @@ -11845,10 +11878,13 @@ snapshots: '@vercel/oidc@3.0.1': {} - '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0))': + '@vitejs/plugin-react@6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 vite: 8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0) + optionalDependencies: + '@rolldown/plugin-babel': 0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + babel-plugin-react-compiler: 1.0.0 '@vitest/expect@4.1.4': dependencies: @@ -12335,6 +12371,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-react-compiler@1.0.0: + dependencies: + '@babel/types': 7.28.4 + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -12644,9 +12684,9 @@ snapshots: compare-versions@6.1.1: {} - composed-offset-position@0.0.6(@floating-ui/utils@0.2.10): + composed-offset-position@0.0.6(@floating-ui/utils@0.2.11): dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.11 compressible@2.0.18: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 05a0e1b1..131ed438 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,6 +4,8 @@ packages: catalog: '@zarrita/storage': ^0.2.0 + '@rolldown/plugin-babel': ^0.2.3 + babel-plugin-react-compiler: ^1.0.0 '@deck.gl/aggregation-layers': ~9.3.5 '@deck.gl/arcgis': ~9.3.5 '@deck.gl/core': ~9.3.5 diff --git a/vite.config.base.ts b/vite.config.base.ts index 1aa2cacf..35842866 100644 --- a/vite.config.base.ts +++ b/vite.config.base.ts @@ -1,6 +1,7 @@ import path from 'node:path'; +import babel from '@rolldown/plugin-babel'; +import react, { reactCompilerPreset } from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; import dts from 'vite-plugin-dts'; export type WorkspaceAlias = { @@ -45,15 +46,22 @@ interface DefineConfigOptions { pkgRoot: string; libName: string; external?: (string | RegExp)[]; + /** + * Enable the React Compiler (babel-plugin-react-compiler) for this package. + * Only opt in for packages that ship React components; the plugin must be a + * dependency of any package that sets this to true. + */ + reactCompiler?: boolean; } export function defineViteConfig(options: DefineConfigOptions) { - const { pkgRoot, libName, external = [] } = options; + const { pkgRoot, libName, external = [], reactCompiler = false } = options; return defineConfig({ root: pkgRoot, plugins: [ react(), + ...(reactCompiler ? [babel({ presets: [reactCompilerPreset()] })] : []), dts({ root: pkgRoot, tsconfigPath: path.resolve(pkgRoot, 'tsconfig.json'), @@ -82,7 +90,14 @@ export function defineViteConfig(options: DefineConfigOptions) { formats: ['es'], }, rollupOptions: { - external: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', ...external], + external: [ + 'react', + 'react-dom', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + 'react/compiler-runtime', + ...external, + ], }, }, }); From 0ba1556cfd6d65bcf798c8141a986e449d98131c Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 29 Jun 2026 17:36:34 +0100 Subject: [PATCH 2/5] Add scoped ESLint react-hooks linting and fix low-risk findings Biome lacks the React Compiler / Rules-of-React analysis, so add a narrowly-scoped ESLint setup (eslint-plugin-react-hooks v7) that runs only against the React-shipping packages via `pnpm lint:react`. Biome remains the primary linter. - eslint.config.mjs: flat config, react-hooks recommended ruleset, scoped to packages/{react,vis}/src. - package.json: add eslint, eslint-plugin-react-hooks, @typescript-eslint/parser devDeps and the lint:react script. - test.yml: add a non-blocking `react-lint` CI job (existing backlog of findings); flip continue-on-error once cleared to make it required. Fix the low-risk findings: - Tree: resolve the display value before returning JSX so a throw from toJSON() is actually caught (JSX is lazy; try/catch around the return is not). - SpatialCanvasViewer: document the two intentional granular dep arrays. useLayerData returns a fresh object each render, so depending on `layerData` would re-run the memo/effect every render; the stable members are the correct deps. The remaining refs / set-state-in-effect findings in the canvas code are left for the tooltip-performance follow-up. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/test.yml | 27 + eslint.config.mjs | 26 + package.json | 4 + .../src/SpatialCanvas/SpatialCanvasViewer.tsx | 8 + packages/vis/src/Tree/index.tsx | 11 +- pnpm-lock.yaml | 509 ++++++++++++++++++ 6 files changed, 581 insertions(+), 4 deletions(-) create mode 100644 eslint.config.mjs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 35531b09..56395db9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,6 +13,33 @@ concurrency: cancel-in-progress: true jobs: + react-lint: + runs-on: ubuntu-latest + # Surfaces React Hooks / React Compiler (Rules-of-React) findings for the + # React-shipping packages via eslint-plugin-react-hooks. Informational for + # now: there is an existing backlog of findings, so this must not gate merges. + # Flip `continue-on-error` to false once the backlog is cleared to make it a + # required check. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version: '24.14.1' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint React packages (react-hooks / react-compiler rules) + run: pnpm lint:react + test: runs-on: ubuntu-latest steps: diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..7afd8374 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,26 @@ +// Scoped ESLint setup that exists ONLY to run the React Hooks / React Compiler +// rules from eslint-plugin-react-hooks v7 against the React-shipping packages. +// Biome remains the primary linter/formatter for the repo (see biome.json); this +// covers the Rules-of-React analysis Biome does not implement. Run via `pnpm lint:react`. +import tsParser from '@typescript-eslint/parser'; +import reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + { + files: ['packages/react/src/**/*.{ts,tsx}', 'packages/vis/src/**/*.{ts,tsx}'], + plugins: { + 'react-hooks': reactHooks, + }, + languageOptions: { + parser: tsParser, + parserOptions: { + sourceType: 'module', + ecmaFeatures: { jsx: true }, + }, + }, + // The full recommended set: rules-of-hooks + exhaustive-deps plus the + // granular React Compiler diagnostics (immutability, refs, purity, globals, + // set-state-in-render/effect, static-components, …). + rules: reactHooks.configs['recommended-latest'].rules, + }, +]; diff --git a/package.json b/package.json index 27796f87..cffad2d7 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "test:proxy": "node scripts/cors-proxy.js", "validate:datasets:js": "node scripts/validate-datasets-js.js", "lint": "biome check .", + "lint:react": "eslint \"packages/react/src/**/*.{ts,tsx}\" \"packages/vis/src/**/*.{ts,tsx}\"", "format": "biome format --write .", "format:check": "biome format .", "dev": "pnpm -r --parallel dev", @@ -42,6 +43,9 @@ "@biomejs/biome": "^1.9.4", "@changesets/changelog-github": "^0.7.0", "@changesets/cli": "^2.31.0", + "@typescript-eslint/parser": "^8.62.0", + "eslint": "^10.6.0", + "eslint-plugin-react-hooks": "^7.1.1", "@rolldown/plugin-babel": "catalog:", "@vitejs/plugin-react": "catalog:", "babel-plugin-react-compiler": "catalog:", diff --git a/packages/vis/src/SpatialCanvas/SpatialCanvasViewer.tsx b/packages/vis/src/SpatialCanvas/SpatialCanvasViewer.tsx index 3e8be19d..76d6c26d 100644 --- a/packages/vis/src/SpatialCanvas/SpatialCanvasViewer.tsx +++ b/packages/vis/src/SpatialCanvas/SpatialCanvasViewer.tsx @@ -231,6 +231,10 @@ export function useSpatialCanvasRendererFromLayerInputs({ }, [externalDeckLayers, generatedDeckLayers, hostDeckLayers, resolvedLayerOrder, sortDeckLayers]); const vivLayerProps = useMemo( () => layerData.getVivLayerProps(), + // useLayerData returns a fresh object every render, so we intentionally depend + // on its stable members (the useCallback'd getter plus the memoized load flags) + // rather than `layerData` itself, which would recompute this on every render. + // eslint-disable-next-line react-hooks/exhaustive-deps [layerData.getVivLayerProps, vivPassthrough, layerData.isBlocking, layerData.isLoading] ); @@ -262,6 +266,10 @@ export function useSpatialCanvasRendererFromLayerInputs({ onViewStateChange( bounds ? viewStateFromBounds(bounds, width, height) : { target: [0, 0], zoom: 0 } ); + // useLayerData returns a fresh object every render, so we intentionally depend + // on its stable members (memoized flag + useCallback'd bounds getter) rather + // than `layerData` itself, which would re-run this effect on every render. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ autoFit, hasEnabledLayers, diff --git a/packages/vis/src/Tree/index.tsx b/packages/vis/src/Tree/index.tsx index 01684b19..9a25f321 100644 --- a/packages/vis/src/Tree/index.tsx +++ b/packages/vis/src/Tree/index.tsx @@ -8,13 +8,16 @@ export default function SpatialDataTree() { if (loading) return
Loading...
; if (error) return
Error: {error.message}
; if (!spatialData) return
No spatial data
; + // Resolve the value to display before rendering: JSX is lazy, so wrapping the + // returned in try/catch would not catch a throw from toJSON(). + let value: object = spatialData; try { const json = spatialData.toJSON(); - if (!json) { - throw new Error('SpatialData.toJSON() falsey, this should never happen'); + if (json) { + value = json; } - return ; } catch { - return ; + value = spatialData; } + return ; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21e7b683..1d1ac269 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,6 +101,9 @@ importers: '@rolldown/plugin-babel': specifier: 'catalog:' version: 0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) + '@typescript-eslint/parser': + specifier: ^8.62.0 + version: 8.62.0(eslint@10.6.0(jiti@1.21.7))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 'catalog:' version: 6.0.1(@rolldown/plugin-babel@0.2.3(@babel/core@7.28.4)(@babel/runtime@7.28.4)(rolldown@1.0.0-rc.15)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@22.18.8)(jiti@1.21.7)(terser@5.44.0)) @@ -110,6 +113,12 @@ importers: babel-plugin-react-compiler: specifier: 'catalog:' version: 1.0.0 + eslint: + specifier: ^10.6.0 + version: 10.6.0(jiti@1.21.7) + eslint-plugin-react-hooks: + specifier: ^7.1.1 + version: 7.1.1(eslint@10.6.0(jiti@1.21.7)) typescript: specifier: 'catalog:' version: 5.9.3 @@ -1920,6 +1929,36 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@esri/arcgis-html-sanitizer@4.1.0': resolution: {integrity: sha512-einEveDJ/k1180NOp78PB/4Hje9eBy3dyOGLLtLn6bSkizpUfCwuYBIXOA7Y3F/k/BsTQXgKqUVwQ0eiscWMdA==} engines: {node: '>=18.0.0'} @@ -1978,6 +2017,26 @@ packages: '@hms-dbmi/viv@0.22.0': resolution: {integrity: sha512-vbkgJPxErB/YGDBHuXCGF39NKEpZ5KCZL52cUxogiunF7Jzx85G/W35ubRfkTmIPbKkNfXcH7m8XPnkZwakG0A==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@inquirer/external-editor@1.0.3': resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -2915,6 +2974,9 @@ packages: '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} @@ -3076,6 +3138,43 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript-eslint/parser@8.62.0': + resolution: {integrity: sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.62.0': + resolution: {integrity: sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.62.0': + resolution: {integrity: sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.62.0': + resolution: {integrity: sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.62.0': + resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.62.0': + resolution: {integrity: sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.62.0': + resolution: {integrity: sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@uidotdev/usehooks@2.4.1': resolution: {integrity: sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg==} engines: {node: '>=16'} @@ -3348,6 +3447,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + address@1.2.2: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} @@ -3403,6 +3507,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} @@ -3546,6 +3653,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.3.1: resolution: {integrity: sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==} @@ -3597,6 +3708,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -4290,6 +4405,9 @@ packages: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deep-strict-equal@0.2.0: resolution: {integrity: sha512-3daSWyvZ/zwJvuMGlzG1O+Ow0YSadGfb3jsh9xoCutv2tWyB9dA4YvR9L9/fSdDZa2dByYQe+TqapSGUrjnkoA==} engines: {node: '>=0.10.0'} @@ -4536,15 +4654,51 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.6.0: + resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -4650,6 +4804,9 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -4693,6 +4850,10 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + file-loader@6.2.0: resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} engines: {node: '>= 10.13.0'} @@ -4719,10 +4880,18 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + find-up@6.3.0: resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true @@ -4733,6 +4902,9 @@ packages: flatpickr@4.6.13: resolution: {integrity: sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + focus-trap@7.6.6: resolution: {integrity: sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q==} @@ -4929,6 +5101,12 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + history@4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} @@ -5377,6 +5555,9 @@ packages: json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -5422,6 +5603,10 @@ packages: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -5531,6 +5716,10 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + locate-path@7.2.0: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5906,6 +6095,10 @@ packages: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -5954,6 +6147,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -6079,6 +6275,10 @@ packages: openjph-wasm@0.1.0: resolution: {integrity: sha512-0AD6EYf6yt762Q3Pu6g0xVGOeK4XRyZ39zIf2YpfzZUBblHVv3hwJsaxpnLWvSmZLXRp61GA7hg2vQ+ssZngRw==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} @@ -6098,6 +6298,10 @@ packages: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + p-limit@4.0.0: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6106,6 +6310,10 @@ packages: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + p-locate@6.0.0: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6675,6 +6883,10 @@ packages: preact@10.27.2: resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -7081,6 +7293,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -7485,9 +7702,19 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -7887,6 +8114,10 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wordwrapjs@5.1.1: resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} engines: {node: '>=12.17'} @@ -7967,6 +8198,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + yocto-queue@1.2.1: resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} engines: {node: '>=12.20'} @@ -7980,6 +8215,12 @@ packages: zarrita@0.7.1: resolution: {integrity: sha512-Nu4liRKJES1kkIjWALXSryglJf2+WJURUxgndklfX+mTBCd0lk4MV797p00lt4NzmU3Bbdbs10uxeN8LWwPyWA==} + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -10433,6 +10674,36 @@ snapshots: tslib: 2.8.1 optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0(jiti@1.21.7))': + dependencies: + eslint: 10.6.0(jiti@1.21.7) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.6.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.2': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + '@esri/arcgis-html-sanitizer@4.1.0': dependencies: xss: 1.0.13 @@ -10535,6 +10806,22 @@ snapshots: - '@luma.gl/webgl' - react + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@inquirer/external-editor@1.0.3(@types/node@22.18.8)': dependencies: chardet: 2.1.1 @@ -11586,6 +11873,8 @@ snapshots: '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 + '@types/esrecurse@4.3.1': {} + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 @@ -11754,6 +12043,58 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@typescript-eslint/parser@8.62.0(eslint@10.6.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.62.0 + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/typescript-estree': 8.62.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.62.0 + debug: 4.4.3 + eslint: 10.6.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@5.9.3) + '@typescript-eslint/types': 8.62.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.62.0': + dependencies: + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/visitor-keys': 8.62.0 + + '@typescript-eslint/tsconfig-utils@8.62.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/types@8.62.0': {} + + '@typescript-eslint/typescript-estree@8.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.62.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@5.9.3) + '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/visitor-keys': 8.62.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.62.0': + dependencies: + '@typescript-eslint/types': 8.62.0 + eslint-visitor-keys: 5.0.1 + '@uidotdev/usehooks@2.4.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: react: 19.2.1 @@ -12160,12 +12501,18 @@ snapshots: dependencies: acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 acorn@8.15.0: {} + acorn@8.17.0: {} + address@1.2.2: {} agent-base@7.1.4: {} @@ -12211,6 +12558,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ajv@8.12.0: dependencies: fast-deep-equal: 3.1.3 @@ -12379,6 +12733,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.3.1: {} base64-js@1.5.1: {} @@ -12454,6 +12810,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.7: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -13200,6 +13560,8 @@ snapshots: deep-extend@0.6.0: {} + deep-is@0.1.4: {} + deep-strict-equal@0.2.0: dependencies: core-assert: 0.2.1 @@ -13415,13 +13777,82 @@ snapshots: escape-string-regexp@5.0.0: {} + eslint-plugin-react-hooks@7.1.1(eslint@10.6.0(jiti@1.21.7)): + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + eslint: 10.6.0(jiti@1.21.7) + hermes-parser: 0.25.1 + zod: 4.1.13 + zod-validation-error: 4.0.2(zod@4.1.13) + transitivePeerDependencies: + - supports-color + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.6.0(jiti@1.21.7): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@1.21.7)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -13560,6 +13991,8 @@ snapshots: fast-json-stable-stringify@2.1.0: {} + fast-levenshtein@2.0.6: {} + fast-uri@3.1.0: {} fast-xml-builder@1.2.0: @@ -13604,6 +14037,10 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + file-loader@6.2.0(webpack@5.102.0): dependencies: loader-utils: 2.0.4 @@ -13640,17 +14077,29 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + find-up@6.3.0: dependencies: locate-path: 7.2.0 path-exists: 5.0.0 + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + flat@5.0.2: {} flatbuffers@24.12.23: {} flatpickr@4.6.13: {} + flatted@3.4.2: {} + focus-trap@7.6.6: dependencies: tabbable: 6.3.0 @@ -13926,6 +14375,12 @@ snapshots: he@1.2.0: {} + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + history@4.10.1: dependencies: '@babel/runtime': 7.28.4 @@ -14353,6 +14808,8 @@ snapshots: json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json5@2.2.3: {} jsonfile@4.0.0: @@ -14397,6 +14854,11 @@ snapshots: leven@3.1.0: {} + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -14488,6 +14950,10 @@ snapshots: dependencies: p-locate: 4.1.0 + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + locate-path@7.2.0: dependencies: p-locate: 6.0.0 @@ -15126,6 +15592,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.7 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -15168,6 +15638,8 @@ snapshots: nanoid@3.3.11: {} + natural-compare@1.4.0: {} + negotiator@0.6.3: {} negotiator@0.6.4: {} @@ -15281,6 +15753,15 @@ snapshots: openjph-wasm@0.1.0: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + outdent@0.5.0: {} p-cancelable@3.0.0: {} @@ -15295,6 +15776,10 @@ snapshots: dependencies: p-try: 2.2.0 + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + p-limit@4.0.0: dependencies: yocto-queue: 1.2.1 @@ -15303,6 +15788,10 @@ snapshots: dependencies: p-limit: 2.3.0 + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + p-locate@6.0.0: dependencies: p-limit: 4.0.0 @@ -15918,6 +16407,8 @@ snapshots: preact@10.27.2: {} + prelude-ls@1.2.1: {} + prettier@2.8.8: {} pretty-error@4.0.0: @@ -16424,6 +16915,8 @@ snapshots: semver@7.7.2: {} + semver@7.8.5: {} + send@0.19.0: dependencies: debug: 2.6.9 @@ -16838,8 +17331,16 @@ snapshots: trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + tslib@2.8.1: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + type-fest@0.21.3: {} type-fest@1.4.0: {} @@ -17262,6 +17763,8 @@ snapshots: wildcard@2.0.1: {} + word-wrap@1.2.5: {} + wordwrapjs@5.1.1: {} wrap-ansi@7.0.0: @@ -17318,6 +17821,8 @@ snapshots: yallist@4.0.0: {} + yocto-queue@0.1.0: {} + yocto-queue@1.2.1: {} zarrita@0.5.1: @@ -17335,6 +17840,10 @@ snapshots: '@zarrita/storage': 0.2.0 numcodecs: 0.3.2 + zod-validation-error@4.0.2(zod@4.1.13): + dependencies: + zod: 4.1.13 + zod@3.25.76: {} zod@4.1.13: {} From e6af9c2f4e0418ed70c030dcd2cc4bb53d4af7e3 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 29 Jun 2026 17:36:34 +0100 Subject: [PATCH 3/5] Add vis-demo launch config .claude/launch.json with a `vis-demo` entry (pnpm --filter @spatialdata/vis dev:demo on port 5173) for previewing the visualization demo. Co-Authored-By: Claude Opus 4.8 --- .claude/launch.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .claude/launch.json diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 00000000..aef62964 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "vis-demo", + "runtimeExecutable": "pnpm", + "runtimeArgs": ["--filter", "@spatialdata/vis", "dev:demo"], + "port": 5173 + } + ] +} From 509cff409f862ddaf103465b14c9a680ca1cc58d Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 29 Jun 2026 17:47:28 +0100 Subject: [PATCH 4/5] Make react-lint CI check non-failing (step-level continue-on-error) Job-level continue-on-error kept the overall workflow green but still reported the react-lint check itself as failed, which trips CI-failure monitors and reads as a broken required check. Move continue-on-error to the lint step so the job concludes green while still running eslint; findings remain visible in the step log. Remove it to make the check a required gate once the lint backlog is cleared. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/test.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 56395db9..6eb85409 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,9 +18,6 @@ jobs: # Surfaces React Hooks / React Compiler (Rules-of-React) findings for the # React-shipping packages via eslint-plugin-react-hooks. Informational for # now: there is an existing backlog of findings, so this must not gate merges. - # Flip `continue-on-error` to false once the backlog is cleared to make it a - # required check. - continue-on-error: true steps: - uses: actions/checkout@v4 @@ -38,6 +35,11 @@ jobs: run: pnpm install --frozen-lockfile - name: Lint React packages (react-hooks / react-compiler rules) + # continue-on-error (at the step, not the job) keeps this check green + # while the backlog exists, so it does not read as a failing/required + # check; findings still show in this step's log. Remove this line once + # `pnpm lint:react` is clean to turn it into a required gate. + continue-on-error: true run: pnpm lint:react test: From 5eebeca67d9dd6ddec417fc90e195dad5c23e176 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Mon, 29 Jun 2026 17:50:31 +0100 Subject: [PATCH 5/5] Harden react-lint CI job token scope Add a minimal `permissions: contents: read` block and set `persist-credentials: false` on checkout for the react-lint job, per CodeRabbit/zizmor review. The lint job only needs read access; this limits token blast radius and avoids persisting checkout credentials. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6eb85409..d9b109da 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,11 +15,15 @@ concurrency: jobs: react-lint: runs-on: ubuntu-latest + permissions: + contents: read # Surfaces React Hooks / React Compiler (Rules-of-React) findings for the # React-shipping packages via eslint-plugin-react-hooks. Informational for # now: there is an existing backlog of findings, so this must not gate merges. steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: Setup pnpm uses: pnpm/action-setup@v4