From 5d82480fe68c3b58175f3458cb5946d66c1b4aa3 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Tue, 18 Aug 2026 01:11:48 -0400 Subject: [PATCH 01/12] feat: add capture session references to scan nodes --- packages/core/src/schema/index.ts | 6 ++- packages/core/src/schema/nodes/scan.test.ts | 47 +++++++++++++++++++++ packages/core/src/schema/nodes/scan.ts | 11 ++++- packages/nodes/src/scan/definition.ts | 11 +++-- packages/nodes/src/scan/renderer.tsx | 20 ++++++--- 5 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 packages/core/src/schema/nodes/scan.test.ts diff --git a/packages/core/src/schema/index.ts b/packages/core/src/schema/index.ts index d11bdec7d1..cb8a3b8d03 100644 --- a/packages/core/src/schema/index.ts +++ b/packages/core/src/schema/index.ts @@ -198,7 +198,11 @@ export { roofFacePointToSegment, segmentPointToRoofWallFace, } from './nodes/roof-segment-walls' -export { ScanNode } from './nodes/scan' +export { + CaptureSessionReference, + type CaptureSessionReferenceInput, + ScanNode, +} from './nodes/scan' export { ShelfNode } from './nodes/shelf' export { SiteNode } from './nodes/site' export { diff --git a/packages/core/src/schema/nodes/scan.test.ts b/packages/core/src/schema/nodes/scan.test.ts new file mode 100644 index 0000000000..f11f56f5e5 --- /dev/null +++ b/packages/core/src/schema/nodes/scan.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, test } from 'bun:test' +import { ScanNode } from './scan' + +describe('ScanNode', () => { + test('keeps legacy GLB-backed scans loadable', () => { + const scan = ScanNode.parse({ + id: 'scan_legacy', + type: 'scan', + url: 'https://cdn.pascal.app/scans/room.glb', + }) + + expect(scan.url).toBe('https://cdn.pascal.app/scans/room.glb') + expect(scan.captureSession).toBeNull() + }) + + test('accepts a capture session without a renderable mesh', () => { + const scan = ScanNode.parse({ + id: 'scan_session', + type: 'scan', + captureSession: { + sessionId: 'session_123', + manifestUrl: '/api/projects/project_1/captures/capture_1/artifacts/manifest.json', + schemaVersion: 1, + }, + }) + + expect(scan.url).toBeNull() + expect(scan.captureSession).toEqual({ + sessionId: 'session_123', + manifestUrl: '/api/projects/project_1/captures/capture_1/artifacts/manifest.json', + schemaVersion: 1, + }) + }) + + test('rejects unsafe manifest URLs', () => { + const result = ScanNode.safeParse({ + id: 'scan_session', + type: 'scan', + captureSession: { + sessionId: 'session_123', + manifestUrl: 'javascript:alert(1)', + }, + }) + + expect(result.success).toBe(false) + }) +}) diff --git a/packages/core/src/schema/nodes/scan.ts b/packages/core/src/schema/nodes/scan.ts index 9f50a1b5e4..a80ea3221a 100644 --- a/packages/core/src/schema/nodes/scan.ts +++ b/packages/core/src/schema/nodes/scan.ts @@ -2,14 +2,23 @@ import { z } from 'zod' import { AssetUrl } from '../asset-url' import { BaseNode, nodeType, objectId } from '../base' +export const CaptureSessionReference = z.object({ + sessionId: z.string().min(1), + manifestUrl: AssetUrl, + schemaVersion: z.number().int().positive().optional(), +}) + export const ScanNode = BaseNode.extend({ id: objectId('scan'), type: nodeType('scan'), - url: AssetUrl, + url: AssetUrl.nullable().default(null), + captureSession: CaptureSessionReference.nullable().default(null), position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]), rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]), scale: z.number().default(1), opacity: z.number().min(0).max(100).default(100), }) +export type CaptureSessionReference = z.infer +export type CaptureSessionReferenceInput = z.input export type ScanNode = z.infer diff --git a/packages/nodes/src/scan/definition.ts b/packages/nodes/src/scan/definition.ts index bc6cc2f704..68a3d9ac98 100644 --- a/packages/nodes/src/scan/definition.ts +++ b/packages/nodes/src/scan/definition.ts @@ -3,16 +3,15 @@ import { scanParametrics } from './parametrics' import { ScanNode } from './schema' /** - * Scan — Stage A. Mesh imported from the capture pipeline (LiDAR / - * photogrammetry). `ScanSystem` handles mesh loading + per-frame - * positioning; renderer mounts the imported geometry. + * Scan — Stage A. Capture-session reference with an optional renderable + * mesh. Raw sensor streams stay in the external session manifest. */ export const scanDefinition: NodeDefinition = { kind: 'scan', // Heavy LiDAR asset: stripped from the bake, re-added live from scene_graph // in the viewer (see plans → Part D; glb-reference-nodes.tsx). bake: 'strip', - schemaVersion: 1, + schemaVersion: 2, schema: ScanNode, category: 'site', @@ -44,13 +43,13 @@ export const scanDefinition: NodeDefinition = { presentation: { label: 'Scan', - description: 'A captured mesh (LiDAR / photogrammetry) imported as a scene reference.', + description: 'A captured session with optional mesh, motion, media, and sensor data.', icon: { kind: 'url', src: '/icons/mesh.webp' }, paletteSection: 'site', paletteOrder: 40, }, mcp: { - description: 'A captured mesh import.', + description: 'A captured session reference with an optional renderable mesh.', }, } diff --git a/packages/nodes/src/scan/renderer.tsx b/packages/nodes/src/scan/renderer.tsx index e05698740c..9c7c3f5349 100644 --- a/packages/nodes/src/scan/renderer.tsx +++ b/packages/nodes/src/scan/renderer.tsx @@ -10,8 +10,6 @@ export const ScanRenderer = ({ node }: { node: ScanNode }) => { const ref = useRef(null!) useRegistry(node.id, 'scan', ref) - const resolvedUrl = useAssetUrl(node.url) - return ( { scale={[node.scale, node.scale, node.scale]} visible={showScans} > - {resolvedUrl && ( - - - - )} + {node.url && } ) } +const ScanAsset = ({ url, opacity }: { url: string; opacity: number }) => { + const resolvedUrl = useAssetUrl(url) + + if (!resolvedUrl) return null + + return ( + + + + ) +} + const ScanModel = ({ url, opacity }: { url: string; opacity: number }) => { const gltf = useGLTFKTX2(url) as any const scene = gltf.scene From 2f7f8b7edca3740ba16b77a5bc6a0f4f40825232 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Wed, 19 Aug 2026 00:32:24 -0400 Subject: [PATCH 02/12] feat(scan): persist capture layer visibility --- packages/core/src/schema/nodes/scan.test.ts | 15 +++++++++++++++ packages/core/src/schema/nodes/scan.ts | 9 +++++++++ packages/nodes/src/scan/definition.ts | 2 +- packages/nodes/src/scan/renderer.tsx | 6 ++++-- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/core/src/schema/nodes/scan.test.ts b/packages/core/src/schema/nodes/scan.test.ts index f11f56f5e5..7e2a930ebb 100644 --- a/packages/core/src/schema/nodes/scan.test.ts +++ b/packages/core/src/schema/nodes/scan.test.ts @@ -11,6 +11,7 @@ describe('ScanNode', () => { expect(scan.url).toBe('https://cdn.pascal.app/scans/room.glb') expect(scan.captureSession).toBeNull() + expect(scan.layers).toEqual({ model: true, deviceMotion: true }) }) test('accepts a capture session without a renderable mesh', () => { @@ -30,6 +31,20 @@ describe('ScanNode', () => { manifestUrl: '/api/projects/project_1/captures/capture_1/artifacts/manifest.json', schemaVersion: 1, }) + expect(scan.layers).toEqual({ model: true, deviceMotion: true }) + }) + + test('persists independent model and device-motion visibility', () => { + const scan = ScanNode.parse({ + id: 'scan_session', + type: 'scan', + layers: { + model: false, + deviceMotion: true, + }, + }) + + expect(scan.layers).toEqual({ model: false, deviceMotion: true }) }) test('rejects unsafe manifest URLs', () => { diff --git a/packages/core/src/schema/nodes/scan.ts b/packages/core/src/schema/nodes/scan.ts index a80ea3221a..7aef940a2c 100644 --- a/packages/core/src/schema/nodes/scan.ts +++ b/packages/core/src/schema/nodes/scan.ts @@ -8,11 +8,19 @@ export const CaptureSessionReference = z.object({ schemaVersion: z.number().int().positive().optional(), }) +export const ScanLayerVisibility = z + .object({ + model: z.boolean().default(true), + deviceMotion: z.boolean().default(true), + }) + .default({ model: true, deviceMotion: true }) + export const ScanNode = BaseNode.extend({ id: objectId('scan'), type: nodeType('scan'), url: AssetUrl.nullable().default(null), captureSession: CaptureSessionReference.nullable().default(null), + layers: ScanLayerVisibility, position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]), rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]), scale: z.number().default(1), @@ -21,4 +29,5 @@ export const ScanNode = BaseNode.extend({ export type CaptureSessionReference = z.infer export type CaptureSessionReferenceInput = z.input +export type ScanLayerVisibility = z.infer export type ScanNode = z.infer diff --git a/packages/nodes/src/scan/definition.ts b/packages/nodes/src/scan/definition.ts index 68a3d9ac98..e137cea8f6 100644 --- a/packages/nodes/src/scan/definition.ts +++ b/packages/nodes/src/scan/definition.ts @@ -11,7 +11,7 @@ export const scanDefinition: NodeDefinition = { // Heavy LiDAR asset: stripped from the bake, re-added live from scene_graph // in the viewer (see plans → Part D; glb-reference-nodes.tsx). bake: 'strip', - schemaVersion: 2, + schemaVersion: 3, schema: ScanNode, category: 'site', diff --git a/packages/nodes/src/scan/renderer.tsx b/packages/nodes/src/scan/renderer.tsx index 9c7c3f5349..db9398076e 100644 --- a/packages/nodes/src/scan/renderer.tsx +++ b/packages/nodes/src/scan/renderer.tsx @@ -16,9 +16,11 @@ export const ScanRenderer = ({ node }: { node: ScanNode }) => { ref={ref} rotation={node.rotation} scale={[node.scale, node.scale, node.scale]} - visible={showScans} + visible={showScans && node.visible} > - {node.url && } + {(node.layers?.model ?? true) && node.url && ( + + )} ) } From 0e71f6b1c9d0367346388b06e4ead84b600e6bc8 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Wed, 19 Aug 2026 10:57:38 -0400 Subject: [PATCH 03/12] feat(capture): add open capture protocol and viewer runtime --- .github/workflows/release.yml | 92 ++++- README.md | 8 +- bun.lock | 58 +++- packages/capture-protocol/README.md | 26 ++ packages/capture-protocol/package.json | 48 +++ packages/capture-protocol/src/index.ts | 41 +++ packages/capture-protocol/src/schema.test.ts | 108 ++++++ packages/capture-protocol/src/schema.ts | 231 +++++++++++++ packages/capture-protocol/src/source.test.ts | 224 ++++++++++++ packages/capture-protocol/src/source.ts | 322 ++++++++++++++++++ packages/capture-protocol/tsconfig.json | 13 + packages/capture-viewer/README.md | 21 ++ packages/capture-viewer/package.json | 63 ++++ packages/capture-viewer/src/asset-url.ts | 14 + .../capture-viewer/src/capture-runtime.tsx | 292 ++++++++++++++++ packages/capture-viewer/src/frame.test.ts | 50 +++ packages/capture-viewer/src/frame.ts | 24 ++ packages/capture-viewer/src/index.ts | 40 +++ .../src/layers/device-motion-layer.tsx | 95 ++++++ .../src/layers/point-cloud-layer.tsx | 129 +++++++ .../src/layers/room-model-layer.tsx | 86 +++++ .../src/point-cloud-layer.test.ts | 27 ++ .../capture-viewer/src/source-state.test.ts | 110 ++++++ packages/capture-viewer/src/source-state.ts | 252 ++++++++++++++ .../src/stream-rendering.test.ts | 34 ++ .../capture-viewer/src/stream-rendering.ts | 62 ++++ .../capture-viewer/src/trajectory.test.ts | 21 ++ packages/capture-viewer/src/trajectory.ts | 106 ++++++ packages/capture-viewer/tsconfig.json | 14 + packages/core/package.json | 1 + packages/core/src/schema/nodes/scan.test.ts | 37 ++ packages/core/src/schema/nodes/scan.ts | 15 +- packages/core/tsconfig.json | 3 +- packages/nodes/src/scan/definition.ts | 4 +- wiki/architecture/README.md | 1 + wiki/architecture/capture-runtime.md | 48 +++ 36 files changed, 2693 insertions(+), 27 deletions(-) create mode 100644 packages/capture-protocol/README.md create mode 100644 packages/capture-protocol/package.json create mode 100644 packages/capture-protocol/src/index.ts create mode 100644 packages/capture-protocol/src/schema.test.ts create mode 100644 packages/capture-protocol/src/schema.ts create mode 100644 packages/capture-protocol/src/source.test.ts create mode 100644 packages/capture-protocol/src/source.ts create mode 100644 packages/capture-protocol/tsconfig.json create mode 100644 packages/capture-viewer/README.md create mode 100644 packages/capture-viewer/package.json create mode 100644 packages/capture-viewer/src/asset-url.ts create mode 100644 packages/capture-viewer/src/capture-runtime.tsx create mode 100644 packages/capture-viewer/src/frame.test.ts create mode 100644 packages/capture-viewer/src/frame.ts create mode 100644 packages/capture-viewer/src/index.ts create mode 100644 packages/capture-viewer/src/layers/device-motion-layer.tsx create mode 100644 packages/capture-viewer/src/layers/point-cloud-layer.tsx create mode 100644 packages/capture-viewer/src/layers/room-model-layer.tsx create mode 100644 packages/capture-viewer/src/point-cloud-layer.test.ts create mode 100644 packages/capture-viewer/src/source-state.test.ts create mode 100644 packages/capture-viewer/src/source-state.ts create mode 100644 packages/capture-viewer/src/stream-rendering.test.ts create mode 100644 packages/capture-viewer/src/stream-rendering.ts create mode 100644 packages/capture-viewer/src/trajectory.test.ts create mode 100644 packages/capture-viewer/src/trajectory.ts create mode 100644 packages/capture-viewer/tsconfig.json create mode 100644 wiki/architecture/capture-runtime.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e5cd8ec94f..560eaeda86 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,8 @@ on: required: true type: choice options: + - capture-protocol + - capture-viewer - core - viewer - editor @@ -128,7 +130,7 @@ jobs: # peerDeps sync below must use shell vars, not env indirection. declare -A NEW_VERSIONS - for pkg in core viewer editor nodes mcp ifc-converter cli; do + for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do if [ "$TARGET" = "$pkg" ] || [ "$TARGET" = "all" ]; then CUR=$(jq -r '.version' packages/$pkg/package.json) NEW=$(bump_version "$CUR") @@ -141,26 +143,77 @@ jobs: fi done - # Sync inter-package references in peerDependencies and devDependencies. + # Sync inter-package references in dependencies, peerDependencies, and devDependencies. # Anything that references a bumped @pascal-app/* package is updated to ^NEW. - for pkg in core viewer editor nodes mcp ifc-converter cli; do + for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do FILE=packages/$pkg/package.json - for dep in core viewer editor nodes mcp ifc-converter cli; do + for dep in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do VAL="${NEW_VERSIONS[$dep]}" [ -z "$VAL" ] && continue jq --arg name "@pascal-app/$dep" --arg v "^$VAL" ' - if .peerDependencies[$name] then .peerDependencies[$name] = $v else . end + if .dependencies[$name] then .dependencies[$name] = $v else . end + | if .peerDependencies[$name] then .peerDependencies[$name] = $v else . end | if .devDependencies[$name] then .devDependencies[$name] = $v else . end ' "$FILE" > tmp.json && mv tmp.json "$FILE" done done echo "=== @pascal-app/* refs after sync ===" - for pkg in core viewer editor nodes mcp ifc-converter cli; do + for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do echo "--- packages/$pkg/package.json ---" - jq '{ peerDependencies: (.peerDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), devDependencies: (.devDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))) }' packages/$pkg/package.json + jq '{ dependencies: (.dependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), peerDependencies: (.peerDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), devDependencies: (.devDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))) }' packages/$pkg/package.json done + # Version and dependency ranges changed after the frozen install. + # Refresh the lockfile so the release commit remains reproducible. + bun install + + # A single-package release may depend on another package introduced + # by this monorepo. Refuse to publish an uninstallable package when + # that dependency is not part of this run and is absent from npm. + RELEASE_PACKAGES="capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli" + if [ "$TARGET" != "all" ]; then + FILE="packages/$TARGET/package.json" + while IFS=$'\t' read -r DEP RANGE; do + SLUG="${DEP#@pascal-app/}" + case " $RELEASE_PACKAGES " in + *" $SLUG "*) + if ! npm view "$DEP@$RANGE" version >/dev/null 2>&1; then + echo "Missing required published dependency: $DEP@$RANGE" + echo "Release $SLUG first or use the all-package release." + exit 1 + fi + ;; + esac + done < <( + jq -r ' + [(.dependencies // {}), (.peerDependencies // {})] + | add + | to_entries[] + | select(.key | startswith("@pascal-app/")) + | [.key, .value] + | @tsv + ' "$FILE" + ) + fi + + - name: Build & publish capture protocol + if: inputs.package == 'capture-protocol' || inputs.package == 'all' + working-directory: packages/capture-protocol + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + bun run build + if [ "${{ inputs.dry-run }}" = "true" ]; then + echo "🏜️ Dry run — would publish @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" + npm publish --dry-run --access public --tag "$NPM_TAG" + elif npm view "@pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" version >/dev/null 2>&1; then + echo "📦 @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION is already published; continuing release recovery" + else + npm publish --access public --tag "$NPM_TAG" + echo "📦 Published @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" + fi + - name: Validate portable editor runtime if: inputs.package == 'cli' || inputs.package == 'all' env: @@ -206,6 +259,23 @@ jobs: echo "📦 Published @pascal-app/viewer@$VIEWER_VERSION" fi + - name: Build & publish capture viewer + if: inputs.package == 'capture-viewer' || inputs.package == 'all' + working-directory: packages/capture-viewer + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + bun run build + if [ "${{ inputs.dry-run }}" = "true" ]; then + echo "🏜️ Dry run — would publish @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" + npm publish --dry-run --access public --tag "$NPM_TAG" + elif npm view "@pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" version >/dev/null 2>&1; then + echo "📦 @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION is already published; continuing release recovery" + else + npm publish --access public --tag "$NPM_TAG" + echo "📦 Published @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" + fi + - name: Publish editor if: inputs.package == 'editor' || inputs.package == 'all' working-directory: packages/editor @@ -298,6 +368,10 @@ jobs: PKGS="" TAGS="" + if [ -n "$CAPTURE_PROTOCOL_VERSION" ]; then + PKGS="$PKGS @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" + TAGS="$TAGS @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" + fi if [ -n "$CORE_VERSION" ]; then PKGS="$PKGS @pascal-app/core@$CORE_VERSION" TAGS="$TAGS @pascal-app/core@$CORE_VERSION" @@ -306,6 +380,10 @@ jobs: PKGS="$PKGS @pascal-app/viewer@$VIEWER_VERSION" TAGS="$TAGS @pascal-app/viewer@$VIEWER_VERSION" fi + if [ -n "$CAPTURE_VIEWER_VERSION" ]; then + PKGS="$PKGS @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" + TAGS="$TAGS @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" + fi if [ -n "$EDITOR_VERSION" ]; then PKGS="$PKGS @pascal-app/editor@$EDITOR_VERSION" TAGS="$TAGS @pascal-app/editor@$EDITOR_VERSION" diff --git a/README.md b/README.md index 79371cef35..cae0e87e14 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,12 @@ troubleshooting. ## Using Published Packages The viewer runtime and built-in node definitions are separate packages. Install the full built-in -viewer set, then load the built-in plugin once before mounting ``: +viewer set, then load the built-in plugin once before mounting ``. Capture sessions are an +optional transport-neutral extension: ```bash npm install @pascal-app/core @pascal-app/viewer @pascal-app/editor @pascal-app/nodes +npm install @pascal-app/capture-protocol @pascal-app/capture-viewer ``` ```typescript @@ -57,6 +59,8 @@ editor/ ├── packages/ │ ├── core/ # Schemas, scene state, and registry contracts │ ├── viewer/ # 3D rendering runtime and shared systems +│ ├── capture-protocol/ # Static/live capture-session contracts +│ ├── capture-viewer/ # Capture source runtime and reference renderers │ ├── editor/ # Editing tools and UI components │ ├── nodes/ # Built-in node definitions, renderers, and systems │ ├── cli/ # Persistent local editor installer and process manager @@ -70,6 +74,8 @@ editor/ |---------|---------------| | **@pascal-app/core** | Node schemas, scene state (Zustand), registry contracts, spatial queries, and event bus | | **@pascal-app/viewer** | 3D rendering via React Three Fiber, shared render systems, default camera/controls, and post-processing | +| **@pascal-app/capture-protocol** | Versioned capture manifests, normalized streams, and transport-neutral static/live sources | +| **@pascal-app/capture-viewer** | Viewer child runtime and reference model, device-motion, and point-cloud layers | | **@pascal-app/editor** | Editing tools, panels, selection, and direct-manipulation UI | | **@pascal-app/nodes** | Built-in registry plugin with node definitions, renderers, geometry, and systems | | **@pascal-app/cli** | Installs and manages a versioned standalone editor runtime and persistent local data | diff --git a/bun.lock b/bun.lock index e1f9995778..a07ff25087 100644 --- a/bun.lock +++ b/bun.lock @@ -99,6 +99,45 @@ "typescript": "7.0.2", }, }, + "packages/capture-protocol": { + "name": "@pascal-app/capture-protocol", + "version": "1.0.0-beta.4", + "dependencies": { + "zod": "^4.3.5", + }, + "devDependencies": { + "@pascal/typescript-config": "*", + "@types/bun": "^1.3.0", + "typescript": "6.0.3", + }, + }, + "packages/capture-viewer": { + "name": "@pascal-app/capture-viewer", + "version": "1.0.0-beta.4", + "devDependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", + "@pascal-app/core": "^1.0.0-beta.4", + "@pascal-app/viewer": "^1.0.0-beta.4", + "@pascal/typescript-config": "*", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.5.0", + "@types/bun": "^1.3.0", + "@types/react": "^19.2.2", + "@types/three": "^0.184.0", + "react": "^19.2.4", + "three": "^0.185.0", + "typescript": "6.0.3", + }, + "peerDependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", + "@pascal-app/core": "^1.0.0-beta.4", + "@pascal-app/viewer": "^1.0.0-beta.4", + "@react-three/drei": "^10", + "@react-three/fiber": "^9", + "react": "^18 || ^19", + "three": "^0.185", + }, + }, "packages/cli": { "name": "@pascal-app/cli", "version": "0.1.5", @@ -118,6 +157,7 @@ "name": "@pascal-app/core", "version": "1.0.0-beta.4", "dependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", "dedent": "^1.7.1", "idb-keyval": "^6.2.2", "mitt": "^3.0.1", @@ -527,7 +567,7 @@ "@mediapipe/tasks-vision": ["@mediapipe/tasks-vision@0.10.17", "", {}, "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg=="], - "@mint/pascal-plugin": ["@mint/pascal-plugin@github:mintdotgg/mint-pascal-plugin#902c546", { "peerDependencies": { "@pascal-app/core": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/editor": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/viewer": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "react": "^18 || ^19", "three": "^0.185" } }, "mintdotgg-mint-pascal-plugin-902c546"], + "@mint/pascal-plugin": ["@mint/pascal-plugin@github:mintdotgg/mint-pascal-plugin#902c546", { "peerDependencies": { "@pascal-app/core": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/editor": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/viewer": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "react": "^18 || ^19", "three": "^0.185" } }, "mintdotgg-mint-pascal-plugin-902c546", "sha512-/itUH9r9OIP8ZPrklW8iWe6B2SDOtlL1m8r9hlVM4Rw5josYtDdkDKQ37FbanvxxuUKcQnukHbtxWe3svRaCrQ=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], @@ -711,6 +751,10 @@ "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.69.0", "", { "os": "win32", "cpu": "x64" }, "sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA=="], + "@pascal-app/capture-protocol": ["@pascal-app/capture-protocol@workspace:packages/capture-protocol"], + + "@pascal-app/capture-viewer": ["@pascal-app/capture-viewer@workspace:packages/capture-viewer"], + "@pascal-app/cli": ["@pascal-app/cli@workspace:packages/cli"], "@pascal-app/core": ["@pascal-app/core@workspace:packages/core"], @@ -725,11 +769,11 @@ "@pascal-app/nodes": ["@pascal-app/nodes@workspace:packages/nodes"], - "@pascal-app/plugin-bones": ["@pascal-app/plugin-bones@github:pascalorg/plugin-bones#f308cf3", { "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "pascalorg-plugin-bones-f308cf3"], + "@pascal-app/plugin-bones": ["@pascal-app/plugin-bones@github:pascalorg/plugin-bones#f308cf3", { "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "pascalorg-plugin-bones-f308cf3", "sha512-M8EafxXEGXce5Ss+fx74PHOt5YgsEpGBrWRg5YllL8lz69ZjQWPFCl75GMwzXOnTgaLrVY5oRcI7mLIaQVz3NQ=="], - "@pascal-app/plugin-streetscape": ["@pascal-app/plugin-streetscape@github:sudhir9297/streetscape-pascal-plugin#1c04ec9", { "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "sudhir9297-streetscape-pascal-plugin-1c04ec9"], + "@pascal-app/plugin-streetscape": ["@pascal-app/plugin-streetscape@github:sudhir9297/streetscape-pascal-plugin#1c04ec9", { "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "sudhir9297-streetscape-pascal-plugin-1c04ec9", "sha512-X7Zg7wi0ghZRcTtbH5LF6xye493uSZ2ft3AmAQBtguBCU6VCwCexA7pdKDr5AnVxX/JRj2s6JSd/OX4aIZ9Y6Q=="], - "@pascal-app/plugin-trees": ["@pascal-app/plugin-trees@github:pascalorg/plugin-trees#56d978c", { "dependencies": { "@dgreenheck/ez-tree": "^1.1.0" }, "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "pascalorg-plugin-trees-56d978c"], + "@pascal-app/plugin-trees": ["@pascal-app/plugin-trees@github:pascalorg/plugin-trees#56d978c", { "dependencies": { "@dgreenheck/ez-tree": "^1.1.0" }, "peerDependencies": { "@pascal-app/core": ">=0.9.1 <1", "@pascal-app/editor": ">=0.9.1 <1", "@pascal-app/viewer": ">=0.9.1 <1", "@react-three/fiber": "^9", "react": "^18 || ^19", "three": "^0.185", "zod": "^4", "zustand": "^5" } }, "pascalorg-plugin-trees-56d978c", "sha512-16VzWot1oadvxCPqsRwMJbaP0a3u5FESFy7F7++pY5wAAFq9JTFwzHvKAsllrY5TZ5TJ7Y5vSqvbmQk8sy8HaA=="], "@pascal-app/viewer": ["@pascal-app/viewer@workspace:packages/viewer"], @@ -1441,7 +1485,7 @@ "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], @@ -2061,8 +2105,6 @@ "postcss/nanoid": ["nanoid@3.3.17", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g=="], - "promise-worker-transferable/is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], - "react-doctor/agent-install": ["agent-install@0.0.5", "", { "dependencies": { "@iarna/toml": "^2.2.5", "commander": "^14.0.0", "jsonc-parser": "^3.3.1", "picocolors": "^1.1.1", "prompts": "^2.4.2", "yaml": "^2.8.3" }, "bin": { "agent-install": "bin/agent-install.mjs" } }, "sha512-nHlms9BkP8ZiY79HrwCGiA2DcNaXrAaJrCM/BEqQ7MEsSKyCk+2A76xPGylIfASZSZE0SaU3T0bNSg4rBPIJAQ=="], "react-doctor/eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.1.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "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" } }, "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g=="], @@ -2071,6 +2113,8 @@ "react-scan/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], + "router/is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "sharp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "three-stdlib/fflate": ["fflate@0.6.10", "", {}, "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg=="], diff --git a/packages/capture-protocol/README.md b/packages/capture-protocol/README.md new file mode 100644 index 0000000000..95729214aa --- /dev/null +++ b/packages/capture-protocol/README.md @@ -0,0 +1,26 @@ +# `@pascal-app/capture-protocol` + +Transport-neutral capture-session contracts for Pascal viewers and hosts. + +The package contains versioned static manifests, a normalized session descriptor, packet headers +for incremental data, and a `CaptureSource` interface that can be backed by HTTP, WebSocket, +WebRTC, local files, or an in-memory producer. It does not contain authentication, persistence, +React, Three.js, or a canonical network transport. + +```ts +import { + createHttpCaptureSource, + type CaptureSessionLocator, +} from '@pascal-app/capture-protocol' + +const locator: CaptureSessionLocator = { + sessionId: 'capture_123', + manifestUrl: '/api/captures/capture_123/manifest', +} + +const source = createHttpCaptureSource(locator, { credentials: 'include' }) +const descriptor = await source.describe() +``` + +For live producers, use `PushCaptureSource` directly or implement `CaptureSource.subscribe()` with +the same descriptor and packet event contract. diff --git a/packages/capture-protocol/package.json b/packages/capture-protocol/package.json new file mode 100644 index 0000000000..32efc7790a --- /dev/null +++ b/packages/capture-protocol/package.json @@ -0,0 +1,48 @@ +{ + "name": "@pascal-app/capture-protocol", + "version": "1.0.0-beta.4", + "description": "Transport-neutral capture-session manifests and live stream sources for Pascal", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "tsc --build", + "dev": "tsgo --build --watch", + "test": "bun test src", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "zod": "^4.3.5" + }, + "devDependencies": { + "@pascal/typescript-config": "*", + "@types/bun": "^1.3.0", + "typescript": "6.0.3" + }, + "keywords": [ + "3d", + "capture", + "point-cloud", + "sensor-fusion", + "streaming" + ], + "repository": { + "type": "git", + "url": "https://github.com/pascalorg/editor.git", + "directory": "packages/capture-protocol" + }, + "license": "MIT", + "homepage": "https://github.com/pascalorg/editor/tree/main/packages/capture-protocol#readme", + "bugs": "https://github.com/pascalorg/editor/issues" +} diff --git a/packages/capture-protocol/src/index.ts b/packages/capture-protocol/src/index.ts new file mode 100644 index 0000000000..3b4a664f97 --- /dev/null +++ b/packages/capture-protocol/src/index.ts @@ -0,0 +1,41 @@ +export { + ArkitDeviceMotionTrajectorySchema, + type CaptureArtifactReference, + CaptureArtifactReferenceSchema, + type CaptureClock, + CaptureClockSchema, + type CaptureCoordinateFrame, + CaptureCoordinateFrameSchema, + type CaptureSessionDescriptor, + CaptureSessionDescriptorSchema, + type CaptureSessionLocator, + CaptureSessionLocatorSchema, + type CaptureSessionManifest, + CaptureSessionManifestSchema, + type CaptureSessionManifestV1, + CaptureSessionManifestV1Schema, + type CaptureSessionManifestV2, + CaptureSessionManifestV2Schema, + type CaptureStreamDescriptor, + CaptureStreamDescriptorSchema, + CaptureTimeRangeSchema, + captureLayerKey, + captureStreamLabel, + DeviceMotionSampleSchema, + type DeviceMotionTrajectoryPayload, + DeviceMotionTrajectorySchema, + normalizeCaptureSessionManifest, +} from './schema' +export { + type CaptureArtifactResolution, + type CaptureSource, + type CaptureSourceEvent, + type CaptureSourceResolver, + type CaptureStreamPacket, + CaptureStreamPacketSchema, + type CaptureSubscriptionOptions, + createHttpCaptureSource, + type HttpCaptureSourceOptions, + PushCaptureSource, + type PushCaptureSourceOptions, +} from './source' diff --git a/packages/capture-protocol/src/schema.test.ts b/packages/capture-protocol/src/schema.test.ts new file mode 100644 index 0000000000..8ded4c1f02 --- /dev/null +++ b/packages/capture-protocol/src/schema.test.ts @@ -0,0 +1,108 @@ +import { describe, expect, test } from 'bun:test' +import { + CaptureSessionManifestV2Schema, + captureLayerKey, + normalizeCaptureSessionManifest, +} from './schema' + +const identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] + +describe('capture manifests', () => { + test('normalizes the Community v1 manifest into extensible streams', () => { + const descriptor = normalizeCaptureSessionManifest({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: { + roomModel: { + kind: 'room-model', + mediaType: 'model/vnd.usdz+zip', + url: 'https://cdn.pascal.app/room.usdz', + }, + deviceMotion: { + kind: 'device-motion', + trajectory: { + coordinateSystem: 'arkit-world', + samples: [ + { segment: 0, timestamp: 0, transform: identity }, + { segment: 0, timestamp: 1, transform: identity }, + ], + }, + }, + }, + }) + + expect(descriptor.streams.map(captureLayerKey)).toEqual(['model', 'deviceMotion']) + expect(descriptor.streams[0]?.artifact?.uri).toBe('https://cdn.pascal.app/room.usdz') + }) + + test('keeps unknown v2 stream kinds without a protocol release', () => { + const manifest = CaptureSessionManifestV2Schema.parse({ + schemaVersion: 2, + sessionId: 'capture_123', + state: 'live', + streams: [ + { + id: 'wifi-rtt', + kind: 'wifi-ranging', + availability: 'live', + }, + ], + }) + + expect(normalizeCaptureSessionManifest(manifest).streams[0]?.kind).toBe('wifi-ranging') + }) + + test('preserves the exact ARKit coordinate system required by v1', () => { + expect(() => + normalizeCaptureSessionManifest({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: { + deviceMotion: { + kind: 'device-motion', + trajectory: { + coordinateSystem: 'unknown', + samples: [ + { segment: 0, timestamp: 0, transform: identity }, + { segment: 0, timestamp: 1, transform: identity }, + ], + }, + }, + }, + }), + ).toThrow() + }) + + test('rejects duplicate stream IDs and backwards time ranges', () => { + expect(() => + normalizeCaptureSessionManifest({ + schemaVersion: 2, + sessionId: 'capture_123', + streams: [ + { id: 'points', kind: 'point-cloud' }, + { id: 'points', kind: 'point-cloud' }, + ], + }), + ).toThrow('Duplicate capture streams id') + + expect(() => + normalizeCaptureSessionManifest({ + schemaVersion: 2, + sessionId: 'capture_123', + streams: [ + { + id: 'video', + kind: 'video', + artifact: { + id: 'video', + mediaType: 'video/mp4', + timeRange: { start: 2, end: 1 }, + }, + }, + ], + }), + ).toThrow('must end at or after') + }) +}) diff --git a/packages/capture-protocol/src/schema.ts b/packages/capture-protocol/src/schema.ts new file mode 100644 index 0000000000..71957bfb6b --- /dev/null +++ b/packages/capture-protocol/src/schema.ts @@ -0,0 +1,231 @@ +import { z } from 'zod' + +const MetadataSchema = z.record(z.string(), z.unknown()) + +export const CaptureSessionLocatorSchema = z.object({ + sessionId: z.string().min(1), + manifestUrl: z.string().min(1).optional(), + schemaVersion: z.number().int().positive().optional(), + revisionId: z.string().min(1).optional(), +}) + +export const DeviceMotionSampleSchema = z.object({ + segment: z.number().int().nonnegative(), + timestamp: z.number().nonnegative(), + transform: z.array(z.number()).length(16), +}) + +export const DeviceMotionTrajectorySchema = z.object({ + coordinateSystem: z.string().min(1), + samples: z.array(DeviceMotionSampleSchema).min(2), +}) + +export const ArkitDeviceMotionTrajectorySchema = DeviceMotionTrajectorySchema.extend({ + coordinateSystem: z.literal('arkit-world'), +}) + +export const CaptureTimeRangeSchema = z + .object({ + start: z.number().nonnegative(), + end: z.number().nonnegative(), + }) + .refine((range) => range.end >= range.start, { + message: 'Capture time ranges must end at or after they start.', + path: ['end'], + }) + +export const CaptureArtifactReferenceSchema = z.object({ + id: z.string().min(1), + uri: z.string().min(1).optional(), + mediaType: z.string().min(1), + byteLength: z.number().int().nonnegative().optional(), + sha256: z.string().min(1).optional(), + frameId: z.string().min(1).optional(), + timeRange: CaptureTimeRangeSchema.optional(), + metadata: MetadataSchema.optional(), +}) + +export const CaptureStreamDescriptorSchema = z.object({ + id: z.string().min(1), + kind: z.string().min(1), + role: z.string().min(1).optional(), + availability: z.enum(['pending', 'live', 'ready', 'failed']).default('ready'), + frameId: z.string().min(1).optional(), + clockId: z.string().min(1).optional(), + artifact: CaptureArtifactReferenceSchema.optional(), + inline: z.unknown().optional(), + metadata: MetadataSchema.optional(), +}) + +export const CaptureClockSchema = z.object({ + id: z.string().min(1), + timebase: z.enum(['seconds', 'milliseconds', 'microseconds', 'nanoseconds']), + epoch: z.string().min(1).optional(), +}) + +export const CaptureCoordinateFrameSchema = z.object({ + id: z.string().min(1), + parentId: z.string().min(1).optional(), + convention: z.string().min(1), + transform: z.array(z.number()).length(16).optional(), +}) + +export const CaptureSessionManifestV1Schema = z.object({ + schemaVersion: z.literal(1), + sessionId: z.string().min(1), + projectId: z.string().min(1), + streams: z.object({ + roomModel: z + .object({ + kind: z.literal('room-model'), + mediaType: z.literal('model/vnd.usdz+zip'), + url: z.string().min(1), + }) + .optional(), + deviceMotion: z + .object({ + kind: z.literal('device-motion'), + trajectory: ArkitDeviceMotionTrajectorySchema, + }) + .optional(), + }), +}) + +export const CaptureSessionManifestV2Schema = z + .object({ + schemaVersion: z.literal(2), + sessionId: z.string().min(1), + projectId: z.string().min(1).optional(), + revisionId: z.string().min(1).optional(), + state: z.enum(['live', 'finalizing', 'ready', 'failed']).default('ready'), + clocks: z.array(CaptureClockSchema).default([]), + coordinateFrames: z.array(CaptureCoordinateFrameSchema).default([]), + streams: z.array(CaptureStreamDescriptorSchema), + metadata: MetadataSchema.optional(), + }) + .superRefine(validateUniqueSessionIds) + +export const CaptureSessionManifestSchema = z.union([ + CaptureSessionManifestV1Schema, + CaptureSessionManifestV2Schema, +]) + +export const CaptureSessionDescriptorSchema = z + .object({ + schemaVersion: z.number().int().positive(), + sessionId: z.string().min(1), + projectId: z.string().min(1).optional(), + revisionId: z.string().min(1).optional(), + state: z.enum(['live', 'finalizing', 'ready', 'failed']), + clocks: z.array(CaptureClockSchema), + coordinateFrames: z.array(CaptureCoordinateFrameSchema), + streams: z.array(CaptureStreamDescriptorSchema), + metadata: MetadataSchema.optional(), + }) + .superRefine(validateUniqueSessionIds) + +export type CaptureArtifactReference = z.infer +export type CaptureClock = z.infer +export type CaptureCoordinateFrame = z.infer +export type CaptureSessionDescriptor = z.infer +export type CaptureSessionLocator = z.infer +export type CaptureSessionManifest = z.infer +export type CaptureSessionManifestV1 = z.infer +export type CaptureSessionManifestV2 = z.infer +export type CaptureStreamDescriptor = z.infer +export type DeviceMotionTrajectoryPayload = z.infer + +export function normalizeCaptureSessionManifest(value: unknown): CaptureSessionDescriptor { + const manifest = CaptureSessionManifestSchema.parse(value) + if (manifest.schemaVersion === 2) return CaptureSessionDescriptorSchema.parse(manifest) + + const streams: CaptureStreamDescriptor[] = [] + if (manifest.streams.roomModel) { + streams.push({ + id: 'room-model', + kind: manifest.streams.roomModel.kind, + role: 'model', + availability: 'ready', + artifact: { + id: `${manifest.sessionId}:room-model`, + mediaType: manifest.streams.roomModel.mediaType, + uri: manifest.streams.roomModel.url, + }, + }) + } + if (manifest.streams.deviceMotion) { + streams.push({ + id: 'device-motion', + kind: manifest.streams.deviceMotion.kind, + role: 'deviceMotion', + availability: 'ready', + inline: manifest.streams.deviceMotion.trajectory, + }) + } + + return CaptureSessionDescriptorSchema.parse({ + schemaVersion: manifest.schemaVersion, + sessionId: manifest.sessionId, + projectId: manifest.projectId, + state: 'ready', + clocks: [], + coordinateFrames: [], + streams, + }) +} + +export function captureLayerKey(stream: CaptureStreamDescriptor): string { + if (stream.role) return stream.role + if (stream.kind === 'room-model') return 'model' + if (stream.kind === 'device-motion') return 'deviceMotion' + if (stream.kind === 'point-cloud') return 'pointCloud' + if (stream.kind === 'gaussian-splat') return 'splat' + return stream.kind +} + +export function captureStreamLabel(stream: CaptureStreamDescriptor): string { + const key = captureLayerKey(stream) + if (key === 'model') return '3D model' + if (key === 'deviceMotion') return 'Device motion' + if (key === 'pointCloud') return 'Point cloud' + if (key === 'splat') return 'Gaussian splat' + return key + .replace(/([a-z])([A-Z])/g, '$1 $2') + .replace(/[-_]+/g, ' ') + .replace(/^./, (value) => value.toUpperCase()) +} + +function validateUniqueSessionIds( + value: { + clocks: Array<{ id: string }> + coordinateFrames: Array<{ id: string }> + streams: Array<{ id: string }> + }, + context: { + addIssue(issue: { code: 'custom'; message: string; path: Array }): void + }, +): void { + validateUniqueIds(value.streams, 'streams', context) + validateUniqueIds(value.clocks, 'clocks', context) + validateUniqueIds(value.coordinateFrames, 'coordinateFrames', context) +} + +function validateUniqueIds( + values: Array<{ id: string }>, + path: string, + context: { + addIssue(issue: { code: 'custom'; message: string; path: Array }): void + }, +): void { + const seen = new Set() + values.forEach((value, index) => { + if (seen.has(value.id)) { + context.addIssue({ + code: 'custom', + message: `Duplicate capture ${path} id: ${value.id}`, + path: [path, index, 'id'], + }) + } + seen.add(value.id) + }) +} diff --git a/packages/capture-protocol/src/source.test.ts b/packages/capture-protocol/src/source.test.ts new file mode 100644 index 0000000000..e5f493f6d4 --- /dev/null +++ b/packages/capture-protocol/src/source.test.ts @@ -0,0 +1,224 @@ +import { describe, expect, test } from 'bun:test' +import type { CaptureSessionDescriptor } from './schema' +import { createHttpCaptureSource, PushCaptureSource } from './source' + +const descriptor: CaptureSessionDescriptor = { + schemaVersion: 2, + sessionId: 'capture_123', + state: 'live', + clocks: [], + coordinateFrames: [], + streams: [ + { id: 'points', kind: 'point-cloud', role: 'pointCloud', availability: 'live' }, + { id: 'motion', kind: 'device-motion', role: 'deviceMotion', availability: 'live' }, + ], +} + +describe('PushCaptureSource', () => { + test('filters live packets by stream and closes the iterator', async () => { + const source = new PushCaptureSource(descriptor) + const iterator = source.subscribe({ streamIds: ['points'] })[Symbol.asyncIterator]() + + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'motion', + generation: 0, + sequence: 0, + timestamp: 0, + payload: {}, + }) + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'points', + generation: 0, + sequence: 1, + timestamp: 0.1, + payload: { positions: [0, 0, 0] }, + }) + + expect((await iterator.next()).value).toMatchObject({ + type: 'packet', + packet: { streamId: 'points', sequence: 1 }, + }) + + source.close() + expect((await iterator.next()).value).toEqual({ type: 'closed' }) + expect((await iterator.next()).done).toBe(true) + }) + + test('rejects packets from another session', () => { + const source = new PushCaptureSource(descriptor) + expect(() => + source.publishPacket({ + protocolVersion: 1, + sessionId: 'capture_other', + streamId: 'points', + generation: 0, + sequence: 0, + timestamp: 0, + payload: {}, + }), + ).toThrow('does not belong') + }) + + test('rejects packets for undeclared streams', () => { + const source = new PushCaptureSource(descriptor) + expect(() => + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'typo', + generation: 0, + sequence: 0, + timestamp: 0, + payload: {}, + }), + ).toThrow('unknown stream') + }) + + test('bounds slow-subscriber queues and keeps the newest packets', async () => { + const source = new PushCaptureSource(descriptor, { maxQueuedEventsPerSubscriber: 2 }) + const iterator = source.subscribe({ streamIds: ['points'] })[Symbol.asyncIterator]() + for (let sequence = 0; sequence < 4; sequence += 1) { + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'points', + generation: 0, + sequence, + timestamp: sequence, + payload: {}, + }) + } + + expect((await iterator.next()).value).toMatchObject({ packet: { sequence: 2 } }) + expect((await iterator.next()).value).toMatchObject({ packet: { sequence: 3 } }) + }) + + test('cancellation clears queued packets', async () => { + const source = new PushCaptureSource(descriptor) + const iterator = source.subscribe()[Symbol.asyncIterator]() + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'points', + generation: 0, + sequence: 0, + timestamp: 0, + payload: {}, + }) + + await iterator.return?.() + expect((await iterator.next()).done).toBe(true) + }) + + test('does not expose mutable descriptor identity', async () => { + const source = new PushCaptureSource(descriptor) + const described = await source.describe() + described.sessionId = 'mutated' + + expect((await source.describe()).sessionId).toBe(descriptor.sessionId) + }) + + test('isolates live event payloads between subscribers', async () => { + const source = new PushCaptureSource(descriptor) + const first = source.subscribe()[Symbol.asyncIterator]() + const second = source.subscribe()[Symbol.asyncIterator]() + source.publishPacket({ + protocolVersion: 1, + sessionId: descriptor.sessionId, + streamId: 'points', + generation: 0, + sequence: 0, + timestamp: 0, + payload: { positions: [0, 0, 0] }, + }) + + const firstEvent = (await first.next()).value + if (firstEvent?.type !== 'packet') throw new Error('Expected a packet event.') + const firstPayload = firstEvent.packet.payload as { positions: number[] } + firstPayload.positions[0] = 99 + + const secondEvent = (await second.next()).value + expect(secondEvent).toMatchObject({ + type: 'packet', + packet: { payload: { positions: [0, 0, 0] } }, + }) + }) +}) + +describe('createHttpCaptureSource', () => { + test('resolves relative artifacts against an absolute manifest URL', async () => { + const source = createHttpCaptureSource( + { + sessionId: 'capture_123', + manifestUrl: 'https://example.com/captures/capture_123/manifest.json', + }, + { + fetch: (async () => + new Response( + JSON.stringify({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: {}, + }), + )) as typeof fetch, + }, + ) + + await source.describe() + await expect( + source.resolveArtifact?.({ id: 'model', mediaType: 'model/gltf-binary', uri: 'room.glb' }), + ).resolves.toEqual({ url: 'https://example.com/captures/capture_123/room.glb' }) + }) + + test('enforces locator schema and revision pins', async () => { + const source = createHttpCaptureSource( + { + sessionId: 'capture_123', + manifestUrl: 'https://example.com/manifest.json', + revisionId: 'revision_expected', + schemaVersion: 2, + }, + { + fetch: (async () => + new Response( + JSON.stringify({ + schemaVersion: 2, + sessionId: 'capture_123', + revisionId: 'revision_other', + streams: [], + }), + )) as typeof fetch, + }, + ) + + await expect(source.describe()).rejects.toThrow('revision does not match') + }) + + test('deduplicates static manifest requests across consumers', async () => { + let requests = 0 + const source = createHttpCaptureSource( + { sessionId: 'capture_123', manifestUrl: 'https://example.com/manifest.json' }, + { + fetch: (async () => { + requests += 1 + return new Response( + JSON.stringify({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: {}, + }), + ) + }) as typeof fetch, + }, + ) + + await Promise.all([source.describe(), source.describe()]) + expect(requests).toBe(1) + }) +}) diff --git a/packages/capture-protocol/src/source.ts b/packages/capture-protocol/src/source.ts new file mode 100644 index 0000000000..21c140f774 --- /dev/null +++ b/packages/capture-protocol/src/source.ts @@ -0,0 +1,322 @@ +import { z } from 'zod' +import { + type CaptureArtifactReference, + type CaptureSessionDescriptor, + CaptureSessionDescriptorSchema, + type CaptureSessionLocator, + CaptureSessionLocatorSchema, + normalizeCaptureSessionManifest, +} from './schema' + +export const CaptureStreamPacketSchema = z.object({ + protocolVersion: z.literal(1), + sessionId: z.string().min(1), + streamId: z.string().min(1), + generation: z.number().int().nonnegative(), + sequence: z.number().int().nonnegative(), + timestamp: z.number().nonnegative(), + frameId: z.string().min(1).optional(), + keyframe: z.boolean().optional(), + bounds: z + .tuple([z.number(), z.number(), z.number(), z.number(), z.number(), z.number()]) + .optional(), + payload: z.unknown(), +}) + +export type CaptureStreamPacket = z.infer + +export type CaptureSourceEvent = + | { type: 'descriptor'; descriptor: CaptureSessionDescriptor } + | { type: 'packet'; packet: CaptureStreamPacket } + | { type: 'closed' } + +export type CaptureArtifactResolution = { + url: string + dispose?: () => void +} + +export type CaptureSubscriptionOptions = { + signal?: AbortSignal + streamIds?: readonly string[] +} + +export interface CaptureSource { + describe(signal?: AbortSignal): Promise + resolveArtifact?( + artifact: CaptureArtifactReference, + signal?: AbortSignal, + ): Promise + subscribe?(options?: CaptureSubscriptionOptions): AsyncIterable +} + +export type CaptureSourceResolver = ( + locator: CaptureSessionLocator, +) => CaptureSource | Promise + +export type HttpCaptureSourceOptions = { + credentials?: RequestCredentials + fetch?: typeof globalThis.fetch + headers?: HeadersInit + manifestUrl?: (locator: CaptureSessionLocator) => string + resolveArtifact?: ( + artifact: CaptureArtifactReference, + signal?: AbortSignal, + ) => Promise +} + +export type PushCaptureSourceOptions = { + maxQueuedEventsPerSubscriber?: number +} + +export function createHttpCaptureSource( + locatorInput: CaptureSessionLocator, + options: HttpCaptureSourceOptions = {}, +): CaptureSource { + const locator = CaptureSessionLocatorSchema.parse(locatorInput) + const manifestUrl = locator.manifestUrl ?? options.manifestUrl?.(locator) + if (!manifestUrl) throw new Error(`Capture session ${locator.sessionId} has no manifest URL.`) + let descriptorPromise: Promise | null = null + + const loadDescriptor = async (): Promise => { + const fetcher = options.fetch ?? globalThis.fetch + const response = await fetcher(manifestUrl, { + credentials: options.credentials, + headers: options.headers, + }) + if (!response.ok) throw new Error(`Capture session ${locator.sessionId} is unavailable.`) + const descriptor = normalizeCaptureSessionManifest(await response.json()) + if (descriptor.sessionId !== locator.sessionId) { + throw new Error(`Capture manifest session does not match ${locator.sessionId}.`) + } + if (locator.schemaVersion && descriptor.schemaVersion !== locator.schemaVersion) { + throw new Error(`Capture manifest schema does not match version ${locator.schemaVersion}.`) + } + if (locator.revisionId && descriptor.revisionId !== locator.revisionId) { + throw new Error(`Capture manifest revision does not match ${locator.revisionId}.`) + } + return descriptor + } + + return { + describe(signal) { + descriptorPromise ??= loadDescriptor().catch((cause: unknown) => { + descriptorPromise = null + throw cause + }) + return waitForPromise(descriptorPromise, signal).then(cloneCaptureDescriptor) + }, + async resolveArtifact(artifact, signal) { + if (options.resolveArtifact) return options.resolveArtifact(artifact, signal) + if (!artifact.uri) throw new Error(`Capture artifact ${artifact.id} has no URI.`) + return { url: resolveArtifactUri(artifact.uri, manifestUrl) } + }, + } +} + +function waitForPromise(promise: Promise, signal?: AbortSignal): Promise { + if (!signal) return promise + if (signal.aborted) return Promise.reject(abortError()) + return new Promise((resolve, reject) => { + const onAbort = () => reject(abortError()) + signal.addEventListener('abort', onAbort, { once: true }) + void promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort)) + }) +} + +function abortError(): Error { + const error = new Error('The capture request was aborted.') + error.name = 'AbortError' + return error +} + +function resolveArtifactUri(uri: string, manifestUrl: string): string { + try { + const base = + typeof globalThis.location === 'undefined' + ? new URL(manifestUrl) + : new URL(manifestUrl, globalThis.location.href) + return new URL(uri, base).toString() + } catch { + return uri + } +} + +type Subscriber = { + iterator: EventIterator + streamIds: Set | null +} + +export class PushCaptureSource implements CaptureSource { + #closed = false + #descriptor: CaptureSessionDescriptor + #maxQueuedEventsPerSubscriber: number + #subscribers = new Set() + + constructor(descriptor: CaptureSessionDescriptor, options: PushCaptureSourceOptions = {}) { + this.#descriptor = cloneCaptureDescriptor(descriptor) + this.#maxQueuedEventsPerSubscriber = Math.max(1, options.maxQueuedEventsPerSubscriber ?? 32) + } + + async describe(): Promise { + return cloneCaptureDescriptor(this.#descriptor) + } + + async resolveArtifact(artifact: CaptureArtifactReference): Promise { + if (!artifact.uri) throw new Error(`Capture artifact ${artifact.id} has no URI.`) + return { url: artifact.uri } + } + + subscribe(options: CaptureSubscriptionOptions = {}): AsyncIterable { + let cleanupAbort = () => {} + let subscriber: Subscriber + const iterator = new EventIterator(() => { + cleanupAbort() + this.#subscribers.delete(subscriber) + }, this.#maxQueuedEventsPerSubscriber) + subscriber = { + iterator, + streamIds: options.streamIds ? new Set(options.streamIds) : null, + } + this.#subscribers.add(subscriber) + if (this.#closed) { + iterator.close({ type: 'closed' }) + } else if (options.signal) { + if (options.signal.aborted) iterator.finish() + else { + const onAbort = () => iterator.finish() + options.signal.addEventListener('abort', onAbort, { once: true }) + cleanupAbort = () => options.signal?.removeEventListener('abort', onAbort) + } + } + return iterator + } + + updateDescriptor(descriptor: CaptureSessionDescriptor): void { + if (this.#closed) return + const nextDescriptor = cloneCaptureDescriptor(descriptor) + if (nextDescriptor.sessionId !== this.#descriptor.sessionId) { + throw new Error('A capture source cannot change session identity.') + } + this.#descriptor = nextDescriptor + this.#publish({ type: 'descriptor', descriptor: cloneCaptureDescriptor(nextDescriptor) }) + } + + publishPacket(packetInput: CaptureStreamPacket): void { + if (this.#closed) return + const packet = CaptureStreamPacketSchema.parse(packetInput) + if (packet.sessionId !== this.#descriptor.sessionId) { + throw new Error(`Capture packet does not belong to ${this.#descriptor.sessionId}.`) + } + if (!this.#descriptor.streams.some((stream) => stream.id === packet.streamId)) { + throw new Error(`Capture packet references unknown stream ${packet.streamId}.`) + } + this.#publish({ type: 'packet', packet }) + } + + close(): void { + if (this.#closed) return + this.#closed = true + for (const subscriber of this.#subscribers) { + subscriber.iterator.close({ type: 'closed' }) + } + this.#subscribers.clear() + } + + #publish(event: CaptureSourceEvent): void { + for (const subscriber of this.#subscribers) { + if ( + event.type === 'packet' && + subscriber.streamIds && + !subscriber.streamIds.has(event.packet.streamId) + ) { + continue + } + subscriber.iterator.push(cloneCaptureSourceEvent(event)) + } + } +} + +class EventIterator implements AsyncIterableIterator { + #done = false + #maxQueuedEvents: number + #onFinish: () => void + #queue: CaptureSourceEvent[] = [] + #waiters: Array<(result: IteratorResult) => void> = [] + + constructor(onFinish: () => void, maxQueuedEvents: number) { + this.#onFinish = onFinish + this.#maxQueuedEvents = maxQueuedEvents + } + + [Symbol.asyncIterator](): AsyncIterableIterator { + return this + } + + next(): Promise> { + const event = this.#queue.shift() + if (event) return Promise.resolve({ done: false, value: event }) + if (this.#done) return Promise.resolve({ done: true, value: undefined }) + return new Promise((resolve) => this.#waiters.push(resolve)) + } + + return(): Promise> { + this.finish() + return Promise.resolve({ done: true, value: undefined }) + } + + push(event: CaptureSourceEvent): void { + if (this.#done) return + const waiter = this.#waiters.shift() + if (waiter) waiter({ done: false, value: event }) + else { + this.#queue.push(event) + this.#trimQueue() + } + } + + close(event: CaptureSourceEvent): void { + if (this.#done) return + this.#done = true + this.#queue = [] + const waiter = this.#waiters.shift() + if (waiter) waiter({ done: false, value: event }) + else this.#queue.push(event) + for (const pending of this.#waiters.splice(0)) pending({ done: true, value: undefined }) + this.#onFinish() + } + + finish(): void { + if (this.#done) { + this.#queue = [] + return + } + this.#done = true + this.#queue = [] + this.#onFinish() + for (const waiter of this.#waiters.splice(0)) waiter({ done: true, value: undefined }) + } + + #trimQueue(): void { + while (this.#queue.length > this.#maxQueuedEvents) { + const packetIndex = this.#queue.findIndex((event) => event.type === 'packet') + this.#queue.splice(packetIndex >= 0 ? packetIndex : 0, 1) + } + } +} + +function cloneCaptureDescriptor(descriptor: CaptureSessionDescriptor): CaptureSessionDescriptor { + return CaptureSessionDescriptorSchema.parse(structuredClone(descriptor)) +} + +function cloneCaptureSourceEvent(event: CaptureSourceEvent): CaptureSourceEvent { + if (event.type === 'descriptor') { + return { type: 'descriptor', descriptor: cloneCaptureDescriptor(event.descriptor) } + } + if (event.type === 'packet') { + return { + type: 'packet', + packet: CaptureStreamPacketSchema.parse(structuredClone(event.packet)), + } + } + return { type: 'closed' } +} diff --git a/packages/capture-protocol/tsconfig.json b/packages/capture-protocol/tsconfig.json new file mode 100644 index 0000000000..06b4bb5999 --- /dev/null +++ b/packages/capture-protocol/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@pascal/typescript-config/react-library.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "noEmit": false, + "composite": true, + "incremental": true, + "types": ["bun"] + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/packages/capture-viewer/README.md b/packages/capture-viewer/README.md new file mode 100644 index 0000000000..44cbfbaea8 --- /dev/null +++ b/packages/capture-viewer/README.md @@ -0,0 +1,21 @@ +# `@pascal-app/capture-viewer` + +Reference capture layers for `@pascal-app/viewer`. + +Mount `CaptureRuntime` as a child of `Viewer` and provide a source resolver. The host owns access +control and transport; the runtime owns source lifecycle, scan-node placement, layer visibility, +and reference renderers for RoomPlan models, device trajectories, and PLY/live point clouds. + +```tsx + + + createHttpCaptureSource(locator, { credentials: 'include' }) + } + /> + +``` + +Unknown streams remain in the descriptor and can be rendered by passing a custom renderer keyed by +stream role or kind. A live transport implements `CaptureSource.subscribe()`; no particular +WebSocket, WebRTC, or collaboration backend is required by this package. diff --git a/packages/capture-viewer/package.json b/packages/capture-viewer/package.json new file mode 100644 index 0000000000..4829d0fa15 --- /dev/null +++ b/packages/capture-viewer/package.json @@ -0,0 +1,63 @@ +{ + "name": "@pascal-app/capture-viewer", + "version": "1.0.0-beta.4", + "description": "Open capture-session runtime and reference renderers for the Pascal viewer", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "tsc --build", + "dev": "tsgo --build --watch", + "test": "bun test src", + "prepublishOnly": "npm run build" + }, + "peerDependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", + "@pascal-app/core": "^1.0.0-beta.4", + "@pascal-app/viewer": "^1.0.0-beta.4", + "@react-three/drei": "^10", + "@react-three/fiber": "^9", + "react": "^18 || ^19", + "three": "^0.185" + }, + "devDependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", + "@pascal-app/core": "^1.0.0-beta.4", + "@pascal-app/viewer": "^1.0.0-beta.4", + "@pascal/typescript-config": "*", + "@react-three/drei": "^10.7.7", + "@react-three/fiber": "^9.5.0", + "@types/bun": "^1.3.0", + "@types/react": "^19.2.2", + "@types/three": "^0.184.0", + "react": "^19.2.4", + "three": "^0.185.0", + "typescript": "6.0.3" + }, + "keywords": [ + "3d", + "capture", + "point-cloud", + "react-three-fiber", + "viewer" + ], + "repository": { + "type": "git", + "url": "https://github.com/pascalorg/editor.git", + "directory": "packages/capture-viewer" + }, + "license": "MIT", + "homepage": "https://github.com/pascalorg/editor/tree/main/packages/capture-viewer#readme", + "bugs": "https://github.com/pascalorg/editor/issues" +} diff --git a/packages/capture-viewer/src/asset-url.ts b/packages/capture-viewer/src/asset-url.ts new file mode 100644 index 0000000000..c0eec374ea --- /dev/null +++ b/packages/capture-viewer/src/asset-url.ts @@ -0,0 +1,14 @@ +export function rewriteLoopbackAssetUrl(value: string): string { + try { + const url = new URL(value) + if ( + typeof window !== 'undefined' && + (url.hostname === '127.0.0.1' || url.hostname === 'localhost') + ) { + url.hostname = window.location.hostname + } + return url.toString() + } catch { + return value + } +} diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx new file mode 100644 index 0000000000..be9729bf80 --- /dev/null +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -0,0 +1,292 @@ +'use client' + +import { + type CaptureArtifactReference, + CaptureArtifactReferenceSchema, + type CaptureArtifactResolution, + type CaptureSessionDescriptor, + type CaptureSessionLocator, + type CaptureSource, + type CaptureSourceResolver, + type CaptureStreamDescriptor, + type CaptureStreamPacket, + captureLayerKey, + DeviceMotionTrajectorySchema, +} from '@pascal-app/capture-protocol' +import { type ScanNode, sceneRegistry, useScene } from '@pascal-app/core' +import { ErrorBoundary, useNodeEvents } from '@pascal-app/viewer' +import { createPortal, useFrame } from '@react-three/fiber' +import { type ComponentType, type ReactNode, Suspense, useEffect, useMemo, useState } from 'react' +import type { Object3D } from 'three' +import { resolveCaptureFrameMatrix } from './frame' +import { CaptureDeviceMotionLayer } from './layers/device-motion-layer' +import { CapturePointCloudLayer } from './layers/point-cloud-layer' +import { CaptureRoomModel } from './layers/room-model-layer' +import { useCaptureSource } from './source-state' +import { + captureModelFormat, + isCaptureModelArtifact, + isCapturePointCloudArtifact, + isCaptureStreamRenderable, +} from './stream-rendering' +import { parseDeviceTrajectoryPackets, parseDeviceTrajectoryPayload } from './trajectory' + +export type CaptureStreamRendererProps = { + artifactUrl: string | null + descriptor: CaptureSessionDescriptor + packets: readonly CaptureStreamPacket[] + scan: ScanNode + source: CaptureSource + stream: CaptureStreamDescriptor + streamEpoch: string +} + +export type CaptureStreamRenderer = ComponentType + +export type CaptureRuntimeProps = { + maxPacketsPerStream?: number + renderers?: Readonly> + resolveSource: CaptureSourceResolver +} + +const EMPTY_RENDERERS: Readonly> = {} + +export function CaptureRuntime({ + maxPacketsPerStream = 32, + renderers = EMPTY_RENDERERS, + resolveSource, +}: CaptureRuntimeProps) { + const nodes = useScene((state) => state.nodes) + const scans = useMemo( + () => + Object.values(nodes).filter( + (node): node is ScanNode => node.type === 'scan' && node.captureSession !== null, + ), + [nodes], + ) + + return ( + <> + {scans.map((scan) => ( + + ))} + + ) +} + +function CaptureSessionPortal({ + maxPacketsPerStream, + renderers, + resolveSource, + scan, +}: { + maxPacketsPerStream: number + renderers: Readonly> + resolveSource: CaptureSourceResolver + scan: ScanNode +}) { + const [target, setTarget] = useState(null) + const handlers = useNodeEvents(scan, 'scan') + const sourceState = useCaptureSource( + scan.captureSession as CaptureSessionLocator, + resolveSource, + { maxPacketsPerStream }, + ) + + useFrame(() => { + const nextTarget = sceneRegistry.nodes.get(scan.id) ?? null + if (nextTarget !== target) setTarget(nextTarget) + }) + + const descriptor = sourceState.descriptor + const source = sourceState.source + const customRendererKeys = useMemo(() => new Set(Object.keys(renderers)), [renderers]) + if (!(target && descriptor && source)) return null + + return createPortal( + + {descriptor.streams.map((stream) => { + const layerKey = captureLayerKey(stream) + if ((scan.layers[layerKey] ?? true) === false) return null + if (!isCaptureStreamRenderable(stream, customRendererKeys)) return null + const renderKey = captureStreamRenderKey(stream) + return ( + } + key={renderKey} + resetKey={`${renderKey}:${sourceState.descriptorVersion}`} + > + + + + + ) + })} + , + target, + ) +} + +function captureStreamRenderKey(stream: CaptureStreamDescriptor): string { + const artifact = stream.artifact + return [ + stream.id, + stream.availability, + artifact?.id ?? '', + artifact?.sha256 ?? '', + artifact?.uri ?? '', + ].join(':') +} + +export function CaptureStreamLayer({ + descriptor, + packets, + renderers, + scan, + source, + stream, + streamEpoch, +}: Omit & { + renderers: Readonly> +}) { + const artifactUrl = useResolvedArtifact(source, stream.artifact) + const layerKey = captureLayerKey(stream) + const Renderer = renderers[layerKey] ?? renderers[stream.kind] + const frameId = packets.at(-1)?.frameId ?? stream.frameId ?? stream.artifact?.frameId + const frameMatrix = useMemo( + () => resolveCaptureFrameMatrix(descriptor, frameId), + [descriptor, frameId], + ) + const trajectory = useMemo(() => { + if (layerKey !== 'deviceMotion') return null + const inline = DeviceMotionTrajectorySchema.safeParse(stream.inline) + return inline.success + ? parseDeviceTrajectoryPayload(inline.data) + : parseDeviceTrajectoryPackets(packets.map((packet) => packet.payload)) + }, [layerKey, packets, stream.inline]) + const motionPlaybackKey = useMemo(() => { + if (layerKey !== 'deviceMotion') return '' + const inlineVersion = packets.length === 0 ? JSON.stringify(stream.inline ?? null) : '' + return [descriptor.revisionId ?? '', streamEpoch, inlineVersion].join(':') + }, [descriptor.revisionId, layerKey, packets.length, stream.inline, streamEpoch]) + if (frameId && !frameMatrix) { + throw new Error(`Capture stream ${stream.id} references an invalid frame: ${frameId}.`) + } + let content: ReactNode = null + if (Renderer) { + content = ( + + ) + } else if ( + layerKey === 'model' && + isCaptureModelArtifact(stream.artifact) && + stream.artifact && + artifactUrl + ) { + content = ( + + ) + } else if (layerKey === 'deviceMotion') { + content = trajectory ? ( + + ) : null + } else if (layerKey === 'pointCloud') { + content = ( + + ) + } + if (!(content && frameMatrix)) return content + return ( + + {content} + + ) +} + +function useResolvedArtifact( + source: CaptureSource, + artifact: CaptureArtifactReference | undefined, +): string | null { + const [error, setError] = useState(null) + const [url, setUrl] = useState(null) + const artifactKey = artifact ? JSON.stringify(artifact) : null + const artifactSnapshot = useMemo( + () => + artifactKey + ? CaptureArtifactReferenceSchema.parse(JSON.parse(artifactKey) as unknown) + : undefined, + [artifactKey], + ) + + useEffect(() => { + const abort = new AbortController() + let dispose: (() => void) | undefined + setError(null) + setUrl(null) + if (!artifactSnapshot) return () => abort.abort() + + const resolve: Promise = source.resolveArtifact + ? source.resolveArtifact(artifactSnapshot, abort.signal) + : artifactSnapshot.uri + ? Promise.resolve({ url: artifactSnapshot.uri }) + : Promise.reject(new Error(`Capture artifact ${artifactSnapshot.id} has no URI.`)) + void resolve + .then((result) => { + if (abort.signal.aborted) { + result.dispose?.() + return + } + dispose = result.dispose + setUrl(result.url) + }) + .catch((cause: unknown) => { + if (!abort.signal.aborted) { + setError( + cause instanceof Error ? cause : new Error('Could not resolve capture artifact.'), + ) + } + }) + return () => { + abort.abort() + dispose?.() + } + }, [artifactSnapshot, source]) + + if (error) throw error + return url +} diff --git a/packages/capture-viewer/src/frame.test.ts b/packages/capture-viewer/src/frame.test.ts new file mode 100644 index 0000000000..2dfe47e19a --- /dev/null +++ b/packages/capture-viewer/src/frame.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test } from 'bun:test' +import type { CaptureSessionDescriptor } from '@pascal-app/capture-protocol' +import { Vector3 } from 'three' +import { resolveCaptureFrameMatrix } from './frame' + +const descriptor: CaptureSessionDescriptor = { + schemaVersion: 2, + sessionId: 'capture_123', + state: 'ready', + clocks: [], + coordinateFrames: [ + { + id: 'world', + convention: 'right-handed-y-up', + transform: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 0, 0, 1], + }, + { + id: 'sensor', + parentId: 'world', + convention: 'arkit-camera', + transform: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1], + }, + ], + streams: [], +} + +describe('resolveCaptureFrameMatrix', () => { + test('composes local-to-parent transforms into session space', () => { + const position = new Vector3(0, 0, 0).applyMatrix4( + resolveCaptureFrameMatrix(descriptor, 'sensor')!, + ) + expect(position.toArray()).toEqual([10, 2, 0]) + }) + + test('returns null for missing or cyclic frame chains', () => { + expect(resolveCaptureFrameMatrix(descriptor, 'missing')).toBeNull() + expect( + resolveCaptureFrameMatrix( + { + ...descriptor, + coordinateFrames: [ + { id: 'a', parentId: 'b', convention: 'test' }, + { id: 'b', parentId: 'a', convention: 'test' }, + ], + }, + 'a', + ), + ).toBeNull() + }) +}) diff --git a/packages/capture-viewer/src/frame.ts b/packages/capture-viewer/src/frame.ts new file mode 100644 index 0000000000..992c40e136 --- /dev/null +++ b/packages/capture-viewer/src/frame.ts @@ -0,0 +1,24 @@ +import type { CaptureSessionDescriptor } from '@pascal-app/capture-protocol' +import { Matrix4 } from 'three' + +export function resolveCaptureFrameMatrix( + descriptor: CaptureSessionDescriptor, + frameId: string | undefined, +): Matrix4 | null { + if (!frameId) return null + const frames = new Map(descriptor.coordinateFrames.map((frame) => [frame.id, frame])) + const visited = new Set() + const matrix = new Matrix4() + let currentId: string | undefined = frameId + + while (currentId) { + if (visited.has(currentId)) return null + visited.add(currentId) + const frame = frames.get(currentId) + if (!frame) return null + if (frame.transform) matrix.premultiply(new Matrix4().fromArray(frame.transform)) + currentId = frame.parentId + } + + return matrix +} diff --git a/packages/capture-viewer/src/index.ts b/packages/capture-viewer/src/index.ts new file mode 100644 index 0000000000..926f6a106f --- /dev/null +++ b/packages/capture-viewer/src/index.ts @@ -0,0 +1,40 @@ +export { rewriteLoopbackAssetUrl } from './asset-url' +export { + CaptureRuntime, + type CaptureRuntimeProps, + CaptureStreamLayer, + type CaptureStreamRenderer, + type CaptureStreamRendererProps, +} from './capture-runtime' +export { resolveCaptureFrameMatrix } from './frame' +export { + CaptureDeviceMotionLayer, + DEVICE_MOTION_PLAYBACK_SPEED, +} from './layers/device-motion-layer' +export { + buildPointCloudData, + CapturePointCloudLayer, + type PointCloudData, +} from './layers/point-cloud-layer' +export { CaptureRoomModel } from './layers/room-model-layer' +export { + appendCapturePacket, + type CaptureSourceState, + type UseCaptureSourceOptions, + useCaptureSource, +} from './source-state' +export { + type CaptureModelFormat, + captureModelFormat, + isCaptureModelArtifact, + isCapturePointCloudArtifact, + isCaptureStreamRenderable, +} from './stream-rendering' +export { + type DeviceTrajectory, + type DeviceTrajectoryFrame, + type DeviceTrajectoryPose, + parseDeviceTrajectoryPackets, + parseDeviceTrajectoryPayload, + sampleDeviceTrajectory, +} from './trajectory' diff --git a/packages/capture-viewer/src/layers/device-motion-layer.tsx b/packages/capture-viewer/src/layers/device-motion-layer.tsx new file mode 100644 index 0000000000..f76f3011c2 --- /dev/null +++ b/packages/capture-viewer/src/layers/device-motion-layer.tsx @@ -0,0 +1,95 @@ +'use client' + +import { Line } from '@react-three/drei' +import { useFrame } from '@react-three/fiber' +import { useMemo, useRef } from 'react' +import { type Group, Quaternion, Vector3 } from 'three' +import { type DeviceTrajectory, sampleDeviceTrajectory } from '../trajectory' + +export const DEVICE_MOTION_PLAYBACK_SPEED = 3 + +export function CaptureDeviceMotionLayer({ + lineWidth = 2.5, + trajectory, +}: { + lineWidth?: number + trajectory: DeviceTrajectory +}) { + const deviceRef = useRef(null) + const elapsedRef = useRef(0) + const position = useMemo(() => new Vector3(), []) + const toPosition = useMemo(() => new Vector3(), []) + const fromQuaternion = useMemo(() => new Quaternion(), []) + const toQuaternion = useMemo(() => new Quaternion(), []) + const trajectorySegments = useMemo(() => { + const segments = new Map() + for (const pose of trajectory.poses) { + const points = segments.get(pose.segment) ?? [] + points.push(pose.position) + segments.set(pose.segment, points) + } + return [...segments.entries()] + .filter(([, points]) => points.length > 1) + .map(([segment, points]) => ({ points, segment })) + }, [trajectory]) + + useFrame((_, delta) => { + if (!deviceRef.current) return + elapsedRef.current += delta * DEVICE_MOTION_PLAYBACK_SPEED + + const frame = sampleDeviceTrajectory(trajectory, elapsedRef.current) + position + .fromArray(frame.from.position) + .lerp(toPosition.fromArray(frame.to.position), frame.alpha) + fromQuaternion.fromArray(frame.from.quaternion) + toQuaternion.fromArray(frame.to.quaternion) + deviceRef.current.position.copy(position) + deviceRef.current.quaternion.slerpQuaternions(fromQuaternion, toQuaternion, frame.alpha) + }) + + return ( + + {trajectorySegments.map(({ points, segment }) => ( + + ))} + + + + + ) +} + +function CameraFrustum({ lineWidth }: { lineWidth: number }) { + const apex: [number, number, number] = [0, 0, 0] + const topRight: [number, number, number] = [0.14, 0.1, -0.28] + const topLeft: [number, number, number] = [-0.14, 0.1, -0.28] + const bottomLeft: [number, number, number] = [-0.14, -0.1, -0.28] + const bottomRight: [number, number, number] = [0.14, -0.1, -0.28] + const corners: [number, number, number][] = [topRight, topLeft, bottomLeft, bottomRight] + const edges = [ + ...corners.map((corner) => [apex, corner] as const), + [topRight, topLeft] as const, + [topLeft, bottomLeft] as const, + [bottomLeft, bottomRight] as const, + [bottomRight, topRight] as const, + ] + + return ( + + {edges.map((points, index) => ( + + ))} + + + + + + ) +} diff --git a/packages/capture-viewer/src/layers/point-cloud-layer.tsx b/packages/capture-viewer/src/layers/point-cloud-layer.tsx new file mode 100644 index 0000000000..b661f1d2cb --- /dev/null +++ b/packages/capture-viewer/src/layers/point-cloud-layer.tsx @@ -0,0 +1,129 @@ +'use client' + +import type { CaptureStreamPacket } from '@pascal-app/capture-protocol' +import { useLoader } from '@react-three/fiber' +import { useEffect, useMemo } from 'react' +import { BufferGeometry, Float32BufferAttribute } from 'three' +import { PLYLoader } from 'three/addons/loaders/PLYLoader.js' +import { rewriteLoopbackAssetUrl } from '../asset-url' + +export type PointCloudData = { + colors: Float32Array | null + positions: Float32Array +} + +export function CapturePointCloudLayer({ + artifactUrl, + maxPoints = 250_000, + packets = [], + pointSize = 0.012, +}: { + artifactUrl?: string + maxPoints?: number + packets?: readonly CaptureStreamPacket[] + pointSize?: number +}) { + const liveData = useMemo(() => buildPointCloudData(packets, maxPoints), [maxPoints, packets]) + if (liveData.positions.length > 0) { + return + } + return artifactUrl ? : null +} + +function PlyPointCloud({ pointSize, url }: { pointSize: number; url: string }) { + const source = useLoader(PLYLoader, rewriteLoopbackAssetUrl(url)) + const geometry = useMemo(() => source.clone(), [source]) + useEffect(() => () => geometry.dispose(), [geometry]) + + return ( + + + + ) +} + +function PointCloudDataLayer({ data, pointSize }: { data: PointCloudData; pointSize: number }) { + const geometry = useMemo(() => { + const next = new BufferGeometry() + next.setAttribute('position', new Float32BufferAttribute(data.positions, 3)) + if (data.colors) next.setAttribute('color', new Float32BufferAttribute(data.colors, 3)) + next.computeBoundingSphere() + return next + }, [data]) + useEffect(() => () => geometry.dispose(), [geometry]) + + return ( + + + + ) +} + +export function buildPointCloudData( + packets: readonly CaptureStreamPacket[], + maxPoints: number, +): PointCloudData { + const chunks: Array<{ colors: number[] | null; positions: number[] }> = [] + let pointCount = 0 + let allHaveColors = true + + for (let index = packets.length - 1; index >= 0 && pointCount < maxPoints; index -= 1) { + const parsed = parsePointPayload(packets[index]?.payload) + if (!parsed) continue + const availablePoints = Math.floor(parsed.positions.length / 3) + const keepPoints = Math.min(availablePoints, maxPoints - pointCount) + if (keepPoints <= 0) continue + const start = (availablePoints - keepPoints) * 3 + chunks.unshift({ + colors: parsed.colors?.slice(start) ?? null, + positions: parsed.positions.slice(start), + }) + pointCount += keepPoints + allHaveColors &&= parsed.colors !== null + } + + const positions = new Float32Array(pointCount * 3) + const colors = allHaveColors && pointCount > 0 ? new Float32Array(pointCount * 3) : null + let offset = 0 + for (const chunk of chunks) { + positions.set(chunk.positions, offset) + if (colors && chunk.colors) colors.set(normalizeColors(chunk.colors), offset) + offset += chunk.positions.length + } + return { colors, positions } +} + +function parsePointPayload( + value: unknown, +): { colors: number[] | null; positions: number[] } | null { + if (!(value && typeof value === 'object')) return null + const payload = value as { colors?: unknown; positions?: unknown } + const positions = numericArray(payload.positions) + if (!(positions && positions.length >= 3 && positions.length % 3 === 0)) return null + const colors = numericArray(payload.colors) + return { + colors: colors && colors.length === positions.length ? colors : null, + positions, + } +} + +function numericArray(value: unknown): number[] | null { + if (Array.isArray(value) && value.every((entry) => typeof entry === 'number')) return value + if (ArrayBuffer.isView(value)) return Array.from(value as unknown as ArrayLike) + return null +} + +function normalizeColors(colors: number[]): number[] { + const divisor = colors.some((value) => value > 1) ? 255 : 1 + return colors.map((value) => Math.min(1, Math.max(0, value / divisor))) +} diff --git a/packages/capture-viewer/src/layers/room-model-layer.tsx b/packages/capture-viewer/src/layers/room-model-layer.tsx new file mode 100644 index 0000000000..a91dee9a87 --- /dev/null +++ b/packages/capture-viewer/src/layers/room-model-layer.tsx @@ -0,0 +1,86 @@ +'use client' + +import { useGLTFKTX2 } from '@pascal-app/viewer' +import { useLoader } from '@react-three/fiber' +import { useEffect, useMemo } from 'react' +import type { Material, Mesh, Object3D } from 'three' +import { USDLoader } from 'three/addons/loaders/USDLoader.js' +import { rewriteLoopbackAssetUrl } from '../asset-url' +import type { CaptureModelFormat } from '../stream-rendering' + +export function CaptureRoomModel({ + format, + mediaType, + opacity = 100, + url, +}: { + format?: CaptureModelFormat + mediaType: string + opacity?: number + url: string +}) { + if ( + format === 'usdz' || + mediaType === 'model/vnd.usdz+zip' || + url.toLowerCase().endsWith('.usdz') + ) { + return + } + return +} + +function UsdzRoomModel({ opacity, url }: { opacity: number; url: string }) { + const source = useLoader(USDLoader, rewriteLoopbackAssetUrl(url)) + const model = useClonedModel(source, opacity) + return +} + +function GlbRoomModel({ opacity, url }: { opacity: number; url: string }) { + const gltf = useGLTFKTX2(rewriteLoopbackAssetUrl(url)) as { scene: Object3D } + const model = useClonedModel(gltf.scene, opacity) + return +} + +function useClonedModel(source: Object3D, opacity: number): Object3D { + const model = useMemo(() => { + const clone = source.clone(true) + clone.traverse((child) => { + const mesh = child as Mesh + if (!mesh.isMesh) return + mesh.material = Array.isArray(mesh.material) + ? mesh.material.map((material) => material.clone()) + : mesh.material.clone() + }) + return clone + }, [source]) + + useEffect(() => { + const normalizedOpacity = opacity / 100 + const transparent = normalizedOpacity < 1 + model.traverse((child) => { + const mesh = child as Mesh + if (!mesh.isMesh) return + const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material] + for (const material of materials) { + material.transparent = transparent + material.opacity = normalizedOpacity + material.depthWrite = !transparent + material.needsUpdate = true + } + }) + }, [model, opacity]) + + useEffect( + () => () => { + model.traverse((child) => { + const mesh = child as Mesh + if (!mesh.isMesh) return + const materials: Material[] = Array.isArray(mesh.material) ? mesh.material : [mesh.material] + for (const material of materials) material.dispose() + }) + }, + [model], + ) + + return model +} diff --git a/packages/capture-viewer/src/point-cloud-layer.test.ts b/packages/capture-viewer/src/point-cloud-layer.test.ts new file mode 100644 index 0000000000..6b0e93f813 --- /dev/null +++ b/packages/capture-viewer/src/point-cloud-layer.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from 'bun:test' +import type { CaptureStreamPacket } from '@pascal-app/capture-protocol' +import { buildPointCloudData } from './layers/point-cloud-layer' + +function packet(sequence: number, positions: number[], colors?: number[]): CaptureStreamPacket { + return { + protocolVersion: 1, + sessionId: 'capture_123', + streamId: 'points', + generation: 0, + sequence, + timestamp: sequence, + payload: { colors, positions }, + } +} + +describe('buildPointCloudData', () => { + test('keeps the newest bounded points and normalizes byte colors', () => { + const data = buildPointCloudData( + [packet(0, [0, 0, 0], [255, 0, 0]), packet(1, [1, 0, 0, 2, 0, 0], [0, 255, 0, 0, 0, 255])], + 2, + ) + + expect([...data.positions]).toEqual([1, 0, 0, 2, 0, 0]) + expect(data.colors ? [...data.colors] : null).toEqual([0, 1, 0, 0, 0, 1]) + }) +}) diff --git a/packages/capture-viewer/src/source-state.test.ts b/packages/capture-viewer/src/source-state.test.ts new file mode 100644 index 0000000000..9aa73be7ee --- /dev/null +++ b/packages/capture-viewer/src/source-state.test.ts @@ -0,0 +1,110 @@ +import { describe, expect, test } from 'bun:test' +import type { CaptureStreamPacket } from '@pascal-app/capture-protocol' +import { + appendCapturePacket, + nextCaptureStreamEpoch, + retainLiveCapturePackets, +} from './source-state' + +function packet(generation: number, sequence: number): CaptureStreamPacket { + return { + protocolVersion: 1, + sessionId: 'capture_123', + streamId: 'points', + generation, + sequence, + timestamp: sequence, + payload: {}, + } +} + +describe('appendCapturePacket', () => { + test('deduplicates, orders, bounds, and resets on a new generation', () => { + let state: Readonly> = {} + state = appendCapturePacket(state, packet(0, 2), 2) + state = appendCapturePacket(state, packet(0, 1), 2) + state = appendCapturePacket(state, packet(0, 2), 2) + expect(state.points?.map((value) => value.sequence)).toEqual([1, 2]) + + state = appendCapturePacket(state, packet(1, 0), 2) + expect(state.points).toEqual([packet(1, 0)]) + expect(appendCapturePacket(state, packet(0, 3), 2)).toBe(state) + }) + + test('resets a stream on keyframes and coordinate-frame changes', () => { + let state: Readonly> = {} + state = appendCapturePacket(state, { ...packet(0, 0), frameId: 'world' }, 4) + state = appendCapturePacket(state, { ...packet(0, 1), frameId: 'world' }, 4) + state = appendCapturePacket(state, { ...packet(0, 2), frameId: 'world', keyframe: true }, 4) + expect(state.points?.map((value) => value.sequence)).toEqual([2]) + + state = appendCapturePacket(state, { ...packet(0, 3), frameId: 'sensor' }, 4) + expect(state.points?.map((value) => value.sequence)).toEqual([3]) + }) + + test('does not let a stale keyframe replace newer live packets', () => { + let state: Readonly> = {} + state = appendCapturePacket(state, { ...packet(0, 5), frameId: 'world' }, 4) + const unchanged = appendCapturePacket( + state, + { ...packet(0, 2), frameId: 'world', keyframe: true }, + 4, + ) + + expect(unchanged).toBe(state) + expect(unchanged.points?.map((value) => value.sequence)).toEqual([5]) + }) + + test('does not reinsert ordinary packets older than an accepted keyframe', () => { + let state: Readonly> = {} + state = appendCapturePacket(state, { ...packet(0, 5), frameId: 'world', keyframe: true }, 4) + const unchanged = appendCapturePacket(state, { ...packet(0, 4), frameId: 'world' }, 4) + + expect(unchanged).toBe(state) + expect(unchanged.points?.map((value) => value.sequence)).toEqual([5]) + }) + + test('keeps a stable playback epoch when a bounded live window advances', () => { + let state: Readonly> = {} + let epoch: string | undefined + const append = (nextPacket: CaptureStreamPacket) => { + const previous = state.points ?? [] + const next = appendCapturePacket(state, nextPacket, 2) + if (next !== state) epoch = nextCaptureStreamEpoch(epoch, previous, nextPacket) + state = next + } + append({ ...packet(0, 0), frameId: 'world' }) + append({ ...packet(0, 1), frameId: 'world' }) + const initialEpoch = epoch + + append({ ...packet(0, 2), frameId: 'world' }) + expect(state.points?.map((value) => value.sequence)).toEqual([1, 2]) + expect(epoch).toBe(initialEpoch) + + append({ ...packet(0, 3), frameId: 'world', keyframe: true }) + expect(epoch).not.toBe(initialEpoch) + const keyframeEpoch = epoch + + append({ ...packet(0, 4), frameId: 'world' }) + expect(epoch).toBe(keyframeEpoch) + + append({ ...packet(1, 0), frameId: 'world' }) + expect(epoch).not.toBe(keyframeEpoch) + }) +}) + +describe('retainLiveCapturePackets', () => { + test('drops preview packets when a stream finalizes', () => { + const packets = { points: [packet(0, 1)] } + expect( + retainLiveCapturePackets(packets, { + schemaVersion: 2, + sessionId: 'capture_123', + state: 'ready', + clocks: [], + coordinateFrames: [], + streams: [{ id: 'points', kind: 'point-cloud', availability: 'ready' }], + }), + ).toEqual({}) + }) +}) diff --git a/packages/capture-viewer/src/source-state.ts b/packages/capture-viewer/src/source-state.ts new file mode 100644 index 0000000000..d3545efcdb --- /dev/null +++ b/packages/capture-viewer/src/source-state.ts @@ -0,0 +1,252 @@ +import type { + CaptureSessionDescriptor, + CaptureSessionLocator, + CaptureSource, + CaptureSourceResolver, + CaptureStreamPacket, +} from '@pascal-app/capture-protocol' +import { useEffect, useState } from 'react' + +export type CaptureSourceState = { + descriptor: CaptureSessionDescriptor | null + descriptorVersion: number + error: Error | null + loading: boolean + packets: Readonly> + source: CaptureSource | null + streamEpochs: Readonly> +} + +export type UseCaptureSourceOptions = { + maxPacketsPerStream?: number + subscribe?: boolean +} + +const EMPTY_PACKETS: Readonly> = {} +const EMPTY_STREAM_EPOCHS: Readonly> = {} + +export function useCaptureSource( + locator: CaptureSessionLocator | null, + resolveSource: CaptureSourceResolver, + options: UseCaptureSourceOptions = {}, +): CaptureSourceState { + const { maxPacketsPerStream = 32, subscribe = true } = options + const [state, setState] = useState({ + descriptor: null, + descriptorVersion: 0, + error: null, + loading: Boolean(locator), + packets: EMPTY_PACKETS, + source: null, + streamEpochs: EMPTY_STREAM_EPOCHS, + }) + + useEffect(() => { + const abort = new AbortController() + if (!locator) { + setState({ + descriptor: null, + descriptorVersion: 0, + error: null, + loading: false, + packets: EMPTY_PACKETS, + source: null, + streamEpochs: EMPTY_STREAM_EPOCHS, + }) + return () => abort.abort() + } + + setState({ + descriptor: null, + descriptorVersion: 0, + error: null, + loading: true, + packets: EMPTY_PACKETS, + source: null, + streamEpochs: EMPTY_STREAM_EPOCHS, + }) + void consumeCaptureSource( + locator, + resolveSource, + abort.signal, + maxPacketsPerStream, + subscribe, + setState, + ) + return () => abort.abort() + }, [locator, maxPacketsPerStream, resolveSource, subscribe]) + + return state +} + +async function consumeCaptureSource( + locator: CaptureSessionLocator, + resolveSource: CaptureSourceResolver, + signal: AbortSignal, + maxPacketsPerStream: number, + subscribe: boolean, + setState: ( + update: CaptureSourceState | ((current: CaptureSourceState) => CaptureSourceState), + ) => void, +): Promise { + try { + const source = await resolveSource(locator) + const descriptor = await source.describe(signal) + if (signal.aborted) return + setState({ + descriptor, + descriptorVersion: 0, + error: null, + loading: false, + packets: EMPTY_PACKETS, + source, + streamEpochs: EMPTY_STREAM_EPOCHS, + }) + + if (!(subscribe && source.subscribe)) return + const iterator = source.subscribe({ signal })[Symbol.asyncIterator]() + const closeIterator = () => void iterator.return?.() + signal.addEventListener('abort', closeIterator, { once: true }) + try { + for (;;) { + const next = await iterator.next() + if (next.done || signal.aborted || next.value.type === 'closed') return + const event = next.value + if (event.type === 'descriptor') { + setState((current) => { + const revisionChanged = + current.descriptor?.revisionId !== event.descriptor.revisionId && + (current.descriptor?.revisionId !== undefined || + event.descriptor.revisionId !== undefined) + return { + ...current, + descriptor: event.descriptor, + descriptorVersion: current.descriptorVersion + 1, + packets: revisionChanged + ? EMPTY_PACKETS + : retainLiveCapturePackets(current.packets, event.descriptor), + streamEpochs: revisionChanged + ? EMPTY_STREAM_EPOCHS + : retainLiveCaptureStreamValues(current.streamEpochs, event.descriptor), + } + }) + } else { + setState((current) => { + const previousPackets = current.packets[event.packet.streamId] ?? [] + const packets = appendCapturePacket(current.packets, event.packet, maxPacketsPerStream) + if (packets === current.packets) return current + return { + ...current, + packets, + streamEpochs: { + ...current.streamEpochs, + [event.packet.streamId]: nextCaptureStreamEpoch( + current.streamEpochs[event.packet.streamId], + previousPackets, + event.packet, + ), + }, + } + }) + } + } + } finally { + signal.removeEventListener('abort', closeIterator) + await iterator.return?.() + } + } catch (cause) { + if (signal.aborted) return + setState({ + descriptor: null, + descriptorVersion: 0, + error: cause instanceof Error ? cause : new Error('Could not load capture session.'), + loading: false, + packets: EMPTY_PACKETS, + source: null, + streamEpochs: EMPTY_STREAM_EPOCHS, + }) + } +} + +export function retainLiveCapturePackets( + packetsByStream: Readonly>, + descriptor: CaptureSessionDescriptor, +): Readonly> { + const liveStreamIds = new Set( + descriptor.streams + .filter((stream) => stream.availability === 'live') + .map((stream) => stream.id), + ) + return Object.fromEntries( + Object.entries(packetsByStream).filter(([streamId]) => liveStreamIds.has(streamId)), + ) +} + +function retainLiveCaptureStreamValues( + valuesByStream: Readonly>, + descriptor: CaptureSessionDescriptor, +): Readonly> { + const liveStreamIds = new Set( + descriptor.streams + .filter((stream) => stream.availability === 'live') + .map((stream) => stream.id), + ) + return Object.fromEntries( + Object.entries(valuesByStream).filter(([streamId]) => liveStreamIds.has(streamId)), + ) +} + +export function appendCapturePacket( + packetsByStream: Readonly>, + packet: CaptureStreamPacket, + maxPacketsPerStream: number, +): Readonly> { + const previous = packetsByStream[packet.streamId] ?? [] + const latest = previous.at(-1) + const currentGeneration = latest?.generation + if (currentGeneration !== undefined && packet.generation < currentGeneration) + return packetsByStream + const resetSequence = previous[0]?.keyframe ? previous[0].sequence : null + if ( + currentGeneration === packet.generation && + resetSequence !== null && + packet.sequence <= resetSequence + ) { + return packetsByStream + } + const resetsStream = Boolean(packet.keyframe) || latest?.frameId !== packet.frameId + if ( + latest && + currentGeneration === packet.generation && + resetsStream && + packet.sequence <= latest.sequence + ) { + return packetsByStream + } + const sameGeneration = currentGeneration === packet.generation && !resetsStream ? previous : [] + if (sameGeneration.some((candidate) => candidate.sequence === packet.sequence)) + return packetsByStream + const limit = Math.max(1, maxPacketsPerStream) + const next = [...sameGeneration, packet] + .sort((left, right) => left.sequence - right.sequence) + .slice(-limit) + return { ...packetsByStream, [packet.streamId]: next } +} + +export function nextCaptureStreamEpoch( + currentEpoch: string | undefined, + previousPackets: readonly CaptureStreamPacket[], + packet: CaptureStreamPacket, +): string { + const latest = previousPackets.at(-1) + const resetsStream = + previousPackets.length === 0 || + latest?.generation !== packet.generation || + latest.frameId !== packet.frameId || + Boolean(packet.keyframe) + if (resetsStream) return `${packet.generation}:${packet.frameId ?? ''}:${packet.sequence}` + return ( + currentEpoch ?? + `${latest.generation}:${latest.frameId ?? ''}:${previousPackets[0]?.sequence ?? latest.sequence}` + ) +} diff --git a/packages/capture-viewer/src/stream-rendering.test.ts b/packages/capture-viewer/src/stream-rendering.test.ts new file mode 100644 index 0000000000..584ff88922 --- /dev/null +++ b/packages/capture-viewer/src/stream-rendering.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'bun:test' +import { isCaptureStreamRenderable } from './stream-rendering' + +describe('isCaptureStreamRenderable', () => { + test('only advertises point-cloud formats handled by the reference renderer', () => { + expect( + isCaptureStreamRenderable({ + id: 'points', + kind: 'point-cloud', + role: 'pointCloud', + availability: 'ready', + artifact: { id: 'points', mediaType: 'application/vnd.las', uri: '/points.las' }, + }), + ).toBe(false) + expect( + isCaptureStreamRenderable({ + id: 'points', + kind: 'point-cloud', + role: 'pointCloud', + availability: 'ready', + artifact: { id: 'points', mediaType: 'application/ply', uri: '/points.ply' }, + }), + ).toBe(true) + }) + + test('allows a host renderer to claim an otherwise unknown stream', () => { + expect( + isCaptureStreamRenderable( + { id: 'splat', kind: 'gaussian-splat', availability: 'ready' }, + new Set(['gaussian-splat']), + ), + ).toBe(true) + }) +}) diff --git a/packages/capture-viewer/src/stream-rendering.ts b/packages/capture-viewer/src/stream-rendering.ts new file mode 100644 index 0000000000..d4b1203a11 --- /dev/null +++ b/packages/capture-viewer/src/stream-rendering.ts @@ -0,0 +1,62 @@ +import { + type CaptureArtifactReference, + type CaptureStreamDescriptor, + captureLayerKey, + DeviceMotionTrajectorySchema, +} from '@pascal-app/capture-protocol' + +const GLB_MEDIA_TYPES = new Set(['model/gltf-binary', 'model/gltf+json']) +const USDZ_MEDIA_TYPES = new Set(['model/vnd.usdz+zip']) +const PLY_MEDIA_TYPES = new Set(['application/ply', 'application/vnd.ply', 'model/ply']) + +export type CaptureModelFormat = 'gltf' | 'usdz' + +export function isCaptureStreamRenderable( + stream: CaptureStreamDescriptor, + customRendererKeys: ReadonlySet = new Set(), +): boolean { + if (stream.availability === 'failed' || stream.availability === 'pending') return false + const layerKey = captureLayerKey(stream) + if (customRendererKeys.has(layerKey) || customRendererKeys.has(stream.kind)) return true + if (layerKey === 'model') return isCaptureModelArtifact(stream.artifact) + if (layerKey === 'deviceMotion') { + return ( + stream.availability === 'live' || + DeviceMotionTrajectorySchema.safeParse(stream.inline).success + ) + } + if (layerKey === 'pointCloud') { + return stream.availability === 'live' || isCapturePointCloudArtifact(stream.artifact) + } + return false +} + +export function isCaptureModelArtifact(artifact: CaptureArtifactReference | undefined): boolean { + return captureModelFormat(artifact) !== null +} + +export function captureModelFormat( + artifact: CaptureArtifactReference | undefined, +): CaptureModelFormat | null { + if (!artifact) return null + if (USDZ_MEDIA_TYPES.has(artifact.mediaType) || hasExtension(artifact.uri, ['.usdz'])) { + return 'usdz' + } + if (GLB_MEDIA_TYPES.has(artifact.mediaType) || hasExtension(artifact.uri, ['.glb', '.gltf'])) { + return 'gltf' + } + return null +} + +export function isCapturePointCloudArtifact( + artifact: CaptureArtifactReference | undefined, +): boolean { + if (!artifact) return false + return PLY_MEDIA_TYPES.has(artifact.mediaType) || hasExtension(artifact.uri, ['.ply']) +} + +function hasExtension(uri: string | undefined, extensions: readonly string[]): boolean { + if (!uri) return false + const path = uri.split(/[?#]/, 1)[0]?.toLowerCase() ?? '' + return extensions.some((extension) => path.endsWith(extension)) +} diff --git a/packages/capture-viewer/src/trajectory.test.ts b/packages/capture-viewer/src/trajectory.test.ts new file mode 100644 index 0000000000..158334bb4a --- /dev/null +++ b/packages/capture-viewer/src/trajectory.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from 'bun:test' +import { parseDeviceTrajectoryPackets } from './trajectory' + +const identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] + +describe('parseDeviceTrajectoryPackets', () => { + test('applies individual samples after the latest full trajectory snapshot', () => { + const trajectory = parseDeviceTrajectoryPackets([ + { + coordinateSystem: 'arkit-world', + samples: [ + { segment: 0, timestamp: 0, transform: identity }, + { segment: 0, timestamp: 1, transform: identity }, + ], + }, + { segment: 0, timestamp: 2, transform: identity }, + ]) + + expect(trajectory?.poses.map((pose) => pose.timestamp)).toEqual([0, 1, 2]) + }) +}) diff --git a/packages/capture-viewer/src/trajectory.ts b/packages/capture-viewer/src/trajectory.ts new file mode 100644 index 0000000000..688f2e6828 --- /dev/null +++ b/packages/capture-viewer/src/trajectory.ts @@ -0,0 +1,106 @@ +import { + DeviceMotionSampleSchema, + type DeviceMotionTrajectoryPayload, + DeviceMotionTrajectorySchema, +} from '@pascal-app/capture-protocol' +import { Matrix4, Quaternion, Vector3 } from 'three' + +export type DeviceTrajectoryPose = { + position: [number, number, number] + quaternion: [number, number, number, number] + segment: number + timestamp: number +} + +export type DeviceTrajectory = { + duration: number + poses: DeviceTrajectoryPose[] +} + +export type DeviceTrajectoryFrame = { + alpha: number + from: DeviceTrajectoryPose + to: DeviceTrajectoryPose +} + +export function parseDeviceTrajectoryPayload( + trajectory: DeviceMotionTrajectoryPayload | null | undefined, +): DeviceTrajectory | null { + if (!trajectory) return null + const parsed = DeviceMotionTrajectorySchema.safeParse(trajectory) + if (!parsed.success) return null + + const poses = parsed.data.samples + .map(parsePose) + .sort((left, right) => left.timestamp - right.timestamp) + if (poses.length < 2) return null + + const firstTimestamp = poses[0]?.timestamp ?? 0 + for (const pose of poses) pose.timestamp -= firstTimestamp + const duration = poses.at(-1)?.timestamp ?? 0 + if (!(duration > 0)) return null + return { duration, poses } +} + +export function parseDeviceTrajectoryPackets( + payloads: readonly unknown[], +): DeviceTrajectory | null { + let coordinateSystem = 'source' + let samples: DeviceMotionTrajectoryPayload['samples'] = [] + for (const payload of payloads) { + const trajectory = DeviceMotionTrajectorySchema.safeParse(payload) + if (trajectory.success) { + coordinateSystem = trajectory.data.coordinateSystem + samples = [...trajectory.data.samples] + continue + } + const sample = DeviceMotionSampleSchema.safeParse(payload) + if (sample.success) samples.push(sample.data) + } + if (samples.length < 2) return null + return parseDeviceTrajectoryPayload({ coordinateSystem, samples }) +} + +export function sampleDeviceTrajectory( + trajectory: DeviceTrajectory, + elapsed: number, +): DeviceTrajectoryFrame { + const time = positiveModulo(elapsed, trajectory.duration) + const poses = trajectory.poses + const first = poses[0] + const last = poses.at(-1) + if (!(first && last)) throw new Error('Device trajectory requires at least two poses.') + let upperIndex = poses.findIndex((pose) => pose.timestamp > time) + + if (upperIndex < 0) upperIndex = poses.length - 1 + if (upperIndex === 0) return { alpha: 0, from: first, to: first } + + const from = poses[upperIndex - 1] ?? first + const to = poses[upperIndex] ?? last + if (from.segment !== to.segment) return { alpha: 0, from, to: from } + + const interval = to.timestamp - from.timestamp + return { + alpha: interval > 0 ? Math.min(1, Math.max(0, (time - from.timestamp) / interval)) : 0, + from, + to, + } +} + +function parsePose(value: DeviceMotionTrajectoryPayload['samples'][number]): DeviceTrajectoryPose { + const matrix = new Matrix4().fromArray(value.transform) + const position = new Vector3() + const quaternion = new Quaternion() + matrix.decompose(position, quaternion, new Vector3()) + + return { + position: [position.x, position.y, position.z], + quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w], + segment: value.segment, + timestamp: value.timestamp, + } +} + +function positiveModulo(value: number, divisor: number): number { + return ((value % divisor) + divisor) % divisor +} diff --git a/packages/capture-viewer/tsconfig.json b/packages/capture-viewer/tsconfig.json new file mode 100644 index 0000000000..3b503afab8 --- /dev/null +++ b/packages/capture-viewer/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@pascal/typescript-config/react-library.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "noEmit": false, + "composite": true, + "incremental": true, + "types": ["bun"] + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"], + "references": [{ "path": "../capture-protocol" }, { "path": "../core" }, { "path": "../viewer" }] +} diff --git a/packages/core/package.json b/packages/core/package.json index 8612ea2e7c..04a142c8ca 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -75,6 +75,7 @@ "three": "^0.185" }, "dependencies": { + "@pascal-app/capture-protocol": "^1.0.0-beta.4", "dedent": "^1.7.1", "idb-keyval": "^6.2.2", "mitt": "^3.0.1", diff --git a/packages/core/src/schema/nodes/scan.test.ts b/packages/core/src/schema/nodes/scan.test.ts index 7e2a930ebb..b223dcbad5 100644 --- a/packages/core/src/schema/nodes/scan.test.ts +++ b/packages/core/src/schema/nodes/scan.test.ts @@ -47,6 +47,43 @@ describe('ScanNode', () => { expect(scan.layers).toEqual({ model: false, deviceMotion: true }) }) + test('preserves known layer defaults when a legacy scene stores a partial map', () => { + const scan = ScanNode.parse({ + id: 'scan_session', + type: 'scan', + layers: { model: false }, + }) + + expect(scan.layers).toEqual({ deviceMotion: true, model: false }) + }) + + test('supports host-resolved sessions and future layer keys', () => { + const scan = ScanNode.parse({ + id: 'scan_session', + type: 'scan', + captureSession: { + sessionId: 'session_123', + revisionId: 'revision_2', + }, + layers: { + model: true, + pointCloud: false, + wifiRanging: true, + }, + }) + + expect(scan.captureSession).toEqual({ + sessionId: 'session_123', + revisionId: 'revision_2', + }) + expect(scan.layers).toEqual({ + deviceMotion: true, + model: true, + pointCloud: false, + wifiRanging: true, + }) + }) + test('rejects unsafe manifest URLs', () => { const result = ScanNode.safeParse({ id: 'scan_session', diff --git a/packages/core/src/schema/nodes/scan.ts b/packages/core/src/schema/nodes/scan.ts index 7aef940a2c..36e16a323a 100644 --- a/packages/core/src/schema/nodes/scan.ts +++ b/packages/core/src/schema/nodes/scan.ts @@ -1,19 +1,16 @@ +import { CaptureSessionLocatorSchema } from '@pascal-app/capture-protocol' import { z } from 'zod' import { AssetUrl } from '../asset-url' import { BaseNode, nodeType, objectId } from '../base' -export const CaptureSessionReference = z.object({ - sessionId: z.string().min(1), - manifestUrl: AssetUrl, - schemaVersion: z.number().int().positive().optional(), +export const CaptureSessionReference = CaptureSessionLocatorSchema.extend({ + manifestUrl: AssetUrl.optional(), }) export const ScanLayerVisibility = z - .object({ - model: z.boolean().default(true), - deviceMotion: z.boolean().default(true), - }) - .default({ model: true, deviceMotion: true }) + .record(z.string().min(1), z.boolean()) + .default({ deviceMotion: true, model: true }) + .transform((layers): Record => ({ deviceMotion: true, model: true, ...layers })) export const ScanNode = BaseNode.extend({ id: objectId('scan'), diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index bf55849b88..957e2ce9cb 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -9,5 +9,6 @@ "types": ["bun"] }, "include": ["src"], - "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"], + "references": [{ "path": "../capture-protocol" }] } diff --git a/packages/nodes/src/scan/definition.ts b/packages/nodes/src/scan/definition.ts index e137cea8f6..5b7f718cab 100644 --- a/packages/nodes/src/scan/definition.ts +++ b/packages/nodes/src/scan/definition.ts @@ -11,7 +11,7 @@ export const scanDefinition: NodeDefinition = { // Heavy LiDAR asset: stripped from the bake, re-added live from scene_graph // in the viewer (see plans → Part D; glb-reference-nodes.tsx). bake: 'strip', - schemaVersion: 3, + schemaVersion: 4, schema: ScanNode, category: 'site', @@ -42,7 +42,7 @@ export const scanDefinition: NodeDefinition = { }, presentation: { - label: 'Scan', + label: 'Capture', description: 'A captured session with optional mesh, motion, media, and sensor data.', icon: { kind: 'url', src: '/icons/mesh.webp' }, paletteSection: 'site', diff --git a/wiki/architecture/README.md b/wiki/architecture/README.md index 51dbf359e6..0ef72a8255 100644 --- a/wiki/architecture/README.md +++ b/wiki/architecture/README.md @@ -17,6 +17,7 @@ Canonical rules for code that touches `packages/core`, `packages/viewer`, `packa | [measurements](measurements.md) | Persistent measurement data, 2D/3D draft ownership, snapping, units, and visibility | | [interaction-scope](interaction-scope.md) | The authoritative interaction state machine ("the spine"): `InteractionScope` union, the begin/update/end/endIf contract, the raycast hot-set, and the overlay scope matrix | | [viewer-isolation](viewer-isolation.md) | Keeping `@pascal-app/viewer` editor-agnostic | +| [capture-runtime](capture-runtime.md) | Open capture protocol, host source boundary, static/live viewer layers, and stream extension | | [selection-managers](selection-managers.md) | Two-layer selection (viewer + editor), events, outliner | | [selection-groups](selection-groups.md) | Session multi-select groups (Ctrl/Cmd+G), expand-on-click, how they differ from collections | | [scene-registry](scene-registry.md) | Global node ID → Object3D map and `useRegistry` | diff --git a/wiki/architecture/capture-runtime.md b/wiki/architecture/capture-runtime.md new file mode 100644 index 0000000000..127e0ff94d --- /dev/null +++ b/wiki/architecture/capture-runtime.md @@ -0,0 +1,48 @@ +# Capture runtime + +Capture data is an optional viewer extension, not a private Community renderer and not a second +scene graph. + +## Package boundaries + +- `@pascal-app/capture-protocol` owns versioned manifests, normalized stream descriptors, stable + session locators, incremental packet headers, and the `CaptureSource` interface. It has no React, + Three.js, authentication, database, or prescribed transport. +- `@pascal-app/capture-viewer` mounts inside `Viewer` through its existing children slot. It resolves + `scan.captureSession`, portals layers into that scan node's registered group, honors per-layer + visibility, composes declared local-to-parent coordinate frames into session space, and supplies + reference model, device-motion, and point-cloud renderers. +- `@pascal-app/core` stores only the scene anchor: session locator, optional current mesh URL, + placement, opacity, and an extensible visibility map. Raw samples and artifact inventories never + enter scene JSON. +- A host owns source resolution, access control, signed URLs, persistence, retention, collaboration, + and transport selection. Community's resolver uses its authenticated capture manifest route. + +## Static and live use the same source + +Every source implements `describe()`. Static HTTP sources stop there. Live sources additionally +implement `subscribe()` and yield descriptor changes or bounded stream packets. The runtime applies +generation and sequence ordering before renderers consume packets. + +The protocol intentionally does not choose WebSocket, WebRTC, Supabase Realtime, or another +transport. An embedded viewer can use a public HTTP manifest; a local tool can use files or an +in-memory producer; Community can layer its collaboration and authorization model on the same +interface. + +Community deliberately does not mount capture artifacts in its public project viewer yet. Its +current manifest route requires edit access; a future public surface needs an explicit view-scoped +artifact and privacy policy before it can use the same runtime safely. + +## Stream extension + +Manifest v2 streams use stable IDs plus open `kind` and `role` strings. Known roles currently map to +`model`, `deviceMotion`, and `pointCloud`. Unknown streams remain available to hosts, which can add a +renderer keyed by role or kind without changing the scene schema. A splat adapter should remain a +separate composited renderer while still consuming the same source and visibility contract. + +## Compatibility + +The protocol normalizes Community's v1 RoomPlan/device-motion manifest, so existing captures remain +viewable. `ScanNode` keeps legacy GLB-backed scans loadable, makes `manifestUrl` optional for +host-resolved sessions, and uses an extensible visibility record so adding a data modality does not +require another node-schema release. From 58dddbe16b20b415e775a4099091b6d8c4af9a42 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Wed, 19 Aug 2026 13:43:38 -0400 Subject: [PATCH 04/12] feat: expose capture streams in the scene tree --- .../src/layers/device-motion-layer.tsx | 66 +++++++++++++--- .../panels/site-panel/registry-tree-node.tsx | 39 ++++++--- .../sidebar/panels/site-panel/tree-node.tsx | 1 + packages/editor/src/index.tsx | 6 ++ .../editor/src/lib/host-tree-children.test.ts | 27 +++++++ packages/editor/src/lib/host-tree-children.ts | 79 +++++++++++++++++++ 6 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 packages/editor/src/lib/host-tree-children.test.ts create mode 100644 packages/editor/src/lib/host-tree-children.ts diff --git a/packages/capture-viewer/src/layers/device-motion-layer.tsx b/packages/capture-viewer/src/layers/device-motion-layer.tsx index f76f3011c2..c4e16b9d2e 100644 --- a/packages/capture-viewer/src/layers/device-motion-layer.tsx +++ b/packages/capture-viewer/src/layers/device-motion-layer.tsx @@ -1,9 +1,16 @@ 'use client' -import { Line } from '@react-three/drei' import { useFrame } from '@react-three/fiber' -import { useMemo, useRef } from 'react' -import { type Group, Quaternion, Vector3 } from 'three' +import { useEffect, useMemo, useRef } from 'react' +import { + BufferGeometry, + type Group, + LineSegments, + Quaternion, + Line as ThreeLine, + Vector3, +} from 'three' +import { LineBasicNodeMaterial } from 'three/webgpu' import { type DeviceTrajectory, sampleDeviceTrajectory } from '../trajectory' export const DEVICE_MOTION_PLAYBACK_SPEED = 3 @@ -50,13 +57,12 @@ export function CaptureDeviceMotionLayer({ return ( {trajectorySegments.map(({ points, segment }) => ( - ))} @@ -73,19 +79,17 @@ function CameraFrustum({ lineWidth }: { lineWidth: number }) { const bottomLeft: [number, number, number] = [-0.14, -0.1, -0.28] const bottomRight: [number, number, number] = [0.14, -0.1, -0.28] const corners: [number, number, number][] = [topRight, topLeft, bottomLeft, bottomRight] - const edges = [ + const points = [ ...corners.map((corner) => [apex, corner] as const), [topRight, topLeft] as const, [topLeft, bottomLeft] as const, [bottomLeft, bottomRight] as const, [bottomRight, topRight] as const, - ] + ].flat() return ( - {edges.map((points, index) => ( - - ))} + @@ -93,3 +97,45 @@ function CameraFrustum({ lineWidth }: { lineWidth: number }) { ) } + +function CaptureLine({ + color, + lineWidth, + opacity = 1, + points, + segments = false, +}: { + color: string + lineWidth: number + opacity?: number + points: readonly [number, number, number][] + segments?: boolean +}) { + const line = useMemo(() => { + const geometry = new BufferGeometry().setFromPoints( + points.map(([x, y, z]) => new Vector3(x, y, z)), + ) + const material = new LineBasicNodeMaterial({ + color, + depthWrite: opacity >= 1, + linewidth: lineWidth, + opacity, + transparent: opacity < 1, + }) + const object = segments + ? new LineSegments(geometry, material) + : new ThreeLine(geometry, material) + object.frustumCulled = false + return object + }, [color, lineWidth, opacity, points, segments]) + + useEffect( + () => () => { + line.geometry.dispose() + line.material.dispose() + }, + [line], + ) + + return +} diff --git a/packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx b/packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx index 5e31e4ff4e..d17fa1bf5a 100644 --- a/packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx @@ -2,8 +2,9 @@ import { Icon as IconifyIcon } from '@iconify/react' import { type AnyNodeId, nodeRegistry, useScene } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import Image from 'next/image' -import { memo, useCallback, useEffect, useState } from 'react' +import { memo, useCallback, useEffect, useState, useSyncExternalStore } from 'react' import { useShallow } from 'zustand/react/shallow' +import { editorHostTreeChildrenRegistry } from '../../../../../lib/host-tree-children' import { resolveNodeSnapTarget, SnapTargetIcon } from '../../../snap-target-badge' import { InlineRenameInput } from './inline-rename-input' import { @@ -43,9 +44,19 @@ export const RegistryTreeNode = memo(function RegistryTreeNode({ const isHovered = useViewer((state) => state.hoveredId === nodeId) const setSelection = useViewer((state) => state.setSelection) const setHoveredId = useViewer((state) => state.setHoveredId) + useSyncExternalStore( + editorHostTreeChildrenRegistry.subscribe, + editorHostTreeChildrenRegistry.getSnapshot, + editorHostTreeChildrenRegistry.getSnapshot, + ) const presentation = node ? nodeRegistry.get(node.type)?.presentation : undefined const tree = node ? nodeRegistry.get(node.type)?.tree : undefined + const hostChildren = node + ? editorHostTreeChildrenRegistry.childrenForKind(node.type) + : undefined + const hasHostChildren = Boolean(node && hostChildren?.hasChildren(node)) + const HostChildren = hasHostChildren ? hostChildren?.component : undefined const icon = presentation?.icon const iconSrc = icon?.kind === 'url' ? icon.src : '/icons/roof.webp' const iconElement = @@ -63,7 +74,7 @@ export const RegistryTreeNode = memo(function RegistryTreeNode({ const snapTarget = resolveNodeSnapTarget(node) const defaultName = node ? tree?.label?.(node, useScene.getState().nodes) || node.name || presentation?.label || 'Node' : 'Node' - const hasChildren = children.length > 0 + const hasChildren = children.length > 0 || hasHostChildren useEffect(() => { return useViewer.subscribe((state) => { @@ -126,15 +137,21 @@ export const RegistryTreeNode = memo(function RegistryTreeNode({ onMouseLeave={() => setHoveredId(null)} onToggle={() => setExpanded((prev) => !prev)} > - {hasChildren && - children.map((childId, index) => ( - - ))} + {hasChildren && ( + <> + {children.map((childId, index) => ( + + ))} + {HostChildren ? ( + + ) : null} + + )} ) }) diff --git a/packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx b/packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx index 8254c83680..ef9dd215b6 100644 --- a/packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/site-panel/tree-node.tsx @@ -169,6 +169,7 @@ const treeNodeByType: Record< 'eyebrow-vent': RegistryTreeNode, skylight: RegistryTreeNode, roof: RoofTreeNode, + scan: RegistryTreeNode, stair: StairTreeNode, door: DoorTreeNode, window: WindowTreeNode, diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx index cd29a02d92..efb016dfc7 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/index.tsx @@ -419,6 +419,12 @@ export { runUndo, subscribeHistoryCommandState, } from './lib/history' +export { + type EditorHostTreeChildren, + type EditorHostTreeChildrenProps, + editorHostTreeChildrenRegistry, + registerEditorHostTreeChildren, +} from './lib/host-tree-children' export { boundaryReshapeScope, curveReshapeScope, diff --git a/packages/editor/src/lib/host-tree-children.test.ts b/packages/editor/src/lib/host-tree-children.test.ts new file mode 100644 index 0000000000..d46f2b8bc3 --- /dev/null +++ b/packages/editor/src/lib/host-tree-children.test.ts @@ -0,0 +1,27 @@ +import { afterEach, describe, expect, test } from 'bun:test' +import { + editorHostTreeChildrenRegistry, + registerEditorHostTreeChildren, +} from './host-tree-children' + +describe('editorHostTreeChildrenRegistry', () => { + afterEach(() => editorHostTreeChildrenRegistry.reset()) + + test('exposes host children by scene node kind and notifies mounted trees', () => { + let notifications = 0 + const unsubscribe = editorHostTreeChildrenRegistry.subscribe(() => { + notifications += 1 + }) + + registerEditorHostTreeChildren({ + kind: 'scan', + component: () => null, + hasChildren: (node) => node.type === 'scan', + }) + + expect(editorHostTreeChildrenRegistry.childrenForKind('scan')).toBeDefined() + expect(editorHostTreeChildrenRegistry.childrenForKind('wall')).toBeUndefined() + expect(notifications).toBe(1) + unsubscribe() + }) +}) diff --git a/packages/editor/src/lib/host-tree-children.ts b/packages/editor/src/lib/host-tree-children.ts new file mode 100644 index 0000000000..1efbfed584 --- /dev/null +++ b/packages/editor/src/lib/host-tree-children.ts @@ -0,0 +1,79 @@ +import type { AnyNode, AnyNodeId } from '@pascal-app/core' +import type { ComponentType } from 'react' + +export type EditorHostTreeChildrenProps = { + nodeId: AnyNodeId + depth: number + parentVisible: boolean +} + +export type EditorHostTreeChildren = { + kind: string + component: ComponentType + hasChildren: (node: AnyNode) => boolean +} + +function isDevMode(): boolean { + try { + const meta = import.meta as { env?: { DEV?: boolean } } + if (typeof meta?.env?.DEV === 'boolean') return meta.env.DEV + } catch { + // import.meta unavailable in some CJS contexts — fall through. + } + if (typeof process !== 'undefined' && process.env?.NODE_ENV) { + return process.env.NODE_ENV !== 'production' + } + return false +} + +class EditorHostTreeChildrenRegistryImpl { + private readonly entries = new Map() + private readonly listeners = new Set<() => void>() + private revision = 0 + + subscribe = (onChange: () => void): (() => void) => { + this.listeners.add(onChange) + return () => { + this.listeners.delete(onChange) + } + } + + getSnapshot = (): number => this.revision + + childrenForKind = (kind: string): EditorHostTreeChildren | undefined => this.entries.get(kind) + + reset(): void { + this.entries.clear() + this.emit() + } + + register(entry: EditorHostTreeChildren): void { + if (typeof entry.kind !== 'string' || entry.kind.length === 0) { + throw new Error('[editor:host-tree-children] kind must be a non-empty string') + } + if (this.entries.has(entry.kind)) { + if (isDevMode()) { + console.warn( + `[editor:host-tree-children] re-registering children for "${entry.kind}" (HMR)`, + ) + } else { + throw new Error( + `[editor:host-tree-children] duplicate kind: "${entry.kind}" already registered`, + ) + } + } + this.entries.set(entry.kind, entry) + this.emit() + } + + private emit(): void { + this.revision += 1 + for (const listener of this.listeners) listener() + } +} + +export const editorHostTreeChildrenRegistry = new EditorHostTreeChildrenRegistryImpl() + +export function registerEditorHostTreeChildren(entry: EditorHostTreeChildren): void { + editorHostTreeChildrenRegistry.register(entry) +} From c211f39d9dce9b3333952c4cc704b37ff3de360f Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Wed, 19 Aug 2026 14:58:49 -0400 Subject: [PATCH 05/12] fix capture motion across renderers --- .../src/layers/device-motion-layer.tsx | 4 +- .../sidebar/panels/settings-panel/index.tsx | 70 ++++++++++++++++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/packages/capture-viewer/src/layers/device-motion-layer.tsx b/packages/capture-viewer/src/layers/device-motion-layer.tsx index c4e16b9d2e..723456b1d9 100644 --- a/packages/capture-viewer/src/layers/device-motion-layer.tsx +++ b/packages/capture-viewer/src/layers/device-motion-layer.tsx @@ -5,12 +5,12 @@ import { useEffect, useMemo, useRef } from 'react' import { BufferGeometry, type Group, + LineBasicMaterial, LineSegments, Quaternion, Line as ThreeLine, Vector3, } from 'three' -import { LineBasicNodeMaterial } from 'three/webgpu' import { type DeviceTrajectory, sampleDeviceTrajectory } from '../trajectory' export const DEVICE_MOTION_PLAYBACK_SPEED = 3 @@ -115,7 +115,7 @@ function CaptureLine({ const geometry = new BufferGeometry().setFromPoints( points.map(([x, y, z]) => new Vector3(x, y, z)), ) - const material = new LineBasicNodeMaterial({ + const material = new LineBasicMaterial({ color, depthWrite: opacity >= 1, linewidth: lineWidth, diff --git a/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx b/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx index e1ad6a8c63..e2f3dbdc27 100644 --- a/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx +++ b/packages/editor/src/components/ui/sidebar/panels/settings-panel/index.tsx @@ -6,11 +6,12 @@ import { } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { TreeView, VisualJson } from '@visual-json/react' -import { Camera, Download, Map as MapIcon, Save, Trash2, Upload } from 'lucide-react' +import { Camera, Check, Copy, Download, Map as MapIcon, Save, Trash2, Upload } from 'lucide-react' import { type KeyboardEvent, type SyntheticEvent, useCallback, + useEffect, useMemo, useRef, useState, @@ -23,6 +24,7 @@ import { DialogTitle, DialogTrigger, } from './../../../../../components/ui/primitives/dialog' +import { Input } from './../../../../../components/ui/primitives/input' import { Switch } from './../../../../../components/ui/primitives/switch' import useEditor, { selectDefaultBuildingAndLevel } from './../../../../../store/use-editor' import useFloorplanMode from './../../../../../store/use-floorplan-mode' @@ -184,6 +186,7 @@ export function SettingsPanel({ onVisibilityChange, }: SettingsPanelProps = {}) { const fileInputRef = useRef(null) + const copyResetTimeoutRef = useRef(null) const nodes = useScene((state) => state.nodes) const rootNodeIds = useScene((state) => state.rootNodeIds) const installedPlugins = useScene((state) => state.installedPlugins) @@ -196,6 +199,9 @@ export function SettingsPanel({ const floorplanMode = useFloorplanMode((state) => state.mode) const [isGeneratingThumbnail, setIsGeneratingThumbnail] = useState(false) const [pendingImport, setPendingImport] = useState(null) + const [projectIdCopyState, setProjectIdCopyState] = useState<'idle' | 'copied' | 'error'>( + 'idle', + ) const sceneGraphValue = useMemo( () => buildSceneGraphValue(nodes as Record, rootNodeIds), [nodes, rootNodeIds], @@ -211,6 +217,15 @@ export function SettingsPanel({ } }, []) + useEffect( + () => () => { + if (copyResetTimeoutRef.current !== null) { + window.clearTimeout(copyResetTimeoutRef.current) + } + }, + [], + ) + const isLocalProject = false // Props-based; only show cloud sections when projectId provided const handleSaveBuild = () => { @@ -310,6 +325,25 @@ export function SettingsPanel({ setTimeout(() => setIsGeneratingThumbnail(false), 3000) } + const handleCopyProjectId = async () => { + if (!projectId) return + if (copyResetTimeoutRef.current !== null) { + window.clearTimeout(copyResetTimeoutRef.current) + } + + try { + await navigator.clipboard.writeText(projectId) + setProjectIdCopyState('copied') + } catch { + setProjectIdCopyState('error') + } + + copyResetTimeoutRef.current = window.setTimeout(() => { + setProjectIdCopyState('idle') + copyResetTimeoutRef.current = null + }, 2000) + } + const handleVisibilityChange = async ( field: 'isPrivate' | 'showScansPublic' | 'showGuidesPublic', value: boolean, @@ -319,6 +353,40 @@ export function SettingsPanel({ return (
+ {projectId && ( +
+ +
Project ID
+
+ + +
+
+ )} + {/* Visibility Section (only for cloud projects) */} {projectId && !isLocalProject && (
From 940b09a8cd4c94d369dff40b37e80ec3f58ff155 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Wed, 19 Aug 2026 17:21:58 -0400 Subject: [PATCH 06/12] feat: add capture layer hierarchy and point clouds --- packages/capture-protocol/src/index.ts | 3 + packages/capture-protocol/src/schema.test.ts | 13 +- packages/capture-protocol/src/schema.ts | 43 +++++ .../capture-viewer/src/capture-runtime.tsx | 1 + .../src/layers/point-cloud-layer.tsx | 23 +++ .../src/point-cloud-layer.test.ts | 15 +- .../src/stream-rendering.test.ts | 12 ++ .../capture-viewer/src/stream-rendering.ts | 7 +- .../components/ui/panels/reference-panel.tsx | 32 +++- .../ui/sidebar/panels/site-panel/index.tsx | 155 +++++++++++++----- packages/nodes/src/scan/definition.ts | 3 + packages/nodes/src/scan/parametrics.ts | 14 +- 12 files changed, 273 insertions(+), 48 deletions(-) diff --git a/packages/capture-protocol/src/index.ts b/packages/capture-protocol/src/index.ts index 3b4a664f97..4f1226444a 100644 --- a/packages/capture-protocol/src/index.ts +++ b/packages/capture-protocol/src/index.ts @@ -1,5 +1,6 @@ export { ArkitDeviceMotionTrajectorySchema, + ArkitPointCloudPayloadSchema, type CaptureArtifactReference, CaptureArtifactReferenceSchema, type CaptureClock, @@ -25,6 +26,8 @@ export { type DeviceMotionTrajectoryPayload, DeviceMotionTrajectorySchema, normalizeCaptureSessionManifest, + type PointCloudPayload, + PointCloudPayloadSchema, } from './schema' export { type CaptureArtifactResolution, diff --git a/packages/capture-protocol/src/schema.test.ts b/packages/capture-protocol/src/schema.test.ts index 8ded4c1f02..55d3054758 100644 --- a/packages/capture-protocol/src/schema.test.ts +++ b/packages/capture-protocol/src/schema.test.ts @@ -29,11 +29,22 @@ describe('capture manifests', () => { ], }, }, + pointCloud: { + kind: 'point-cloud', + points: { + coordinateSystem: 'arkit-world', + positions: [0, 0, 0, 1, 1, 1], + }, + }, }, }) - expect(descriptor.streams.map(captureLayerKey)).toEqual(['model', 'deviceMotion']) + expect(descriptor.streams.map(captureLayerKey)).toEqual(['model', 'deviceMotion', 'pointCloud']) expect(descriptor.streams[0]?.artifact?.uri).toBe('https://cdn.pascal.app/room.usdz') + expect(descriptor.streams[2]?.inline).toMatchObject({ + coordinateSystem: 'arkit-world', + positions: [0, 0, 0, 1, 1, 1], + }) }) test('keeps unknown v2 stream kinds without a protocol release', () => { diff --git a/packages/capture-protocol/src/schema.ts b/packages/capture-protocol/src/schema.ts index 71957bfb6b..73794afdc1 100644 --- a/packages/capture-protocol/src/schema.ts +++ b/packages/capture-protocol/src/schema.ts @@ -24,6 +24,33 @@ export const ArkitDeviceMotionTrajectorySchema = DeviceMotionTrajectorySchema.ex coordinateSystem: z.literal('arkit-world'), }) +export const PointCloudPayloadSchema = z + .object({ + coordinateSystem: z.string().min(1), + positions: z.array(z.number()).min(3), + colors: z.array(z.number()).optional(), + }) + .superRefine((payload, context) => { + if (payload.positions.length % 3 !== 0) { + context.addIssue({ + code: 'custom', + message: 'Point-cloud positions must contain XYZ triples.', + path: ['positions'], + }) + } + if (payload.colors && payload.colors.length !== payload.positions.length) { + context.addIssue({ + code: 'custom', + message: 'Point-cloud colors must match the positions array length.', + path: ['colors'], + }) + } + }) + +export const ArkitPointCloudPayloadSchema = PointCloudPayloadSchema.safeExtend({ + coordinateSystem: z.literal('arkit-world'), +}) + export const CaptureTimeRangeSchema = z .object({ start: z.number().nonnegative(), @@ -88,6 +115,12 @@ export const CaptureSessionManifestV1Schema = z.object({ trajectory: ArkitDeviceMotionTrajectorySchema, }) .optional(), + pointCloud: z + .object({ + kind: z.literal('point-cloud'), + points: ArkitPointCloudPayloadSchema, + }) + .optional(), }), }) @@ -134,6 +167,7 @@ export type CaptureSessionManifestV1 = z.infer export type CaptureStreamDescriptor = z.infer export type DeviceMotionTrajectoryPayload = z.infer +export type PointCloudPayload = z.infer export function normalizeCaptureSessionManifest(value: unknown): CaptureSessionDescriptor { const manifest = CaptureSessionManifestSchema.parse(value) @@ -162,6 +196,15 @@ export function normalizeCaptureSessionManifest(value: unknown): CaptureSessionD inline: manifest.streams.deviceMotion.trajectory, }) } + if (manifest.streams.pointCloud) { + streams.push({ + id: 'point-cloud', + kind: manifest.streams.pointCloud.kind, + role: 'pointCloud', + availability: 'ready', + inline: manifest.streams.pointCloud.points, + }) + } return CaptureSessionDescriptorSchema.parse({ schemaVersion: manifest.schemaVersion, diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index be9729bf80..e99a6c5412 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -226,6 +226,7 @@ export function CaptureStreamLayer({ artifactUrl={ isCapturePointCloudArtifact(stream.artifact) ? (artifactUrl ?? undefined) : undefined } + inline={stream.inline} packets={stream.availability === 'live' ? packets : []} /> ) diff --git a/packages/capture-viewer/src/layers/point-cloud-layer.tsx b/packages/capture-viewer/src/layers/point-cloud-layer.tsx index b661f1d2cb..49d99e2f01 100644 --- a/packages/capture-viewer/src/layers/point-cloud-layer.tsx +++ b/packages/capture-viewer/src/layers/point-cloud-layer.tsx @@ -14,19 +14,28 @@ export type PointCloudData = { export function CapturePointCloudLayer({ artifactUrl, + inline, maxPoints = 250_000, packets = [], pointSize = 0.012, }: { artifactUrl?: string + inline?: unknown maxPoints?: number packets?: readonly CaptureStreamPacket[] pointSize?: number }) { const liveData = useMemo(() => buildPointCloudData(packets, maxPoints), [maxPoints, packets]) + const inlineData = useMemo( + () => buildPointCloudPayloadData(inline, maxPoints), + [inline, maxPoints], + ) if (liveData.positions.length > 0) { return } + if (inlineData.positions.length > 0) { + return + } return artifactUrl ? : null } @@ -103,6 +112,20 @@ export function buildPointCloudData( return { colors, positions } } +export function buildPointCloudPayloadData(value: unknown, maxPoints: number): PointCloudData { + const parsed = parsePointPayload(value) + if (!parsed) return { colors: null, positions: new Float32Array() } + + const availablePoints = Math.floor(parsed.positions.length / 3) + const keepPoints = Math.min(availablePoints, maxPoints) + const start = (availablePoints - keepPoints) * 3 + const positions = new Float32Array(parsed.positions.slice(start)) + const colors = parsed.colors + ? new Float32Array(normalizeColors(parsed.colors.slice(start))) + : null + return { colors, positions } +} + function parsePointPayload( value: unknown, ): { colors: number[] | null; positions: number[] } | null { diff --git a/packages/capture-viewer/src/point-cloud-layer.test.ts b/packages/capture-viewer/src/point-cloud-layer.test.ts index 6b0e93f813..0d2a41cdd1 100644 --- a/packages/capture-viewer/src/point-cloud-layer.test.ts +++ b/packages/capture-viewer/src/point-cloud-layer.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'bun:test' import type { CaptureStreamPacket } from '@pascal-app/capture-protocol' -import { buildPointCloudData } from './layers/point-cloud-layer' +import { buildPointCloudData, buildPointCloudPayloadData } from './layers/point-cloud-layer' function packet(sequence: number, positions: number[], colors?: number[]): CaptureStreamPacket { return { @@ -24,4 +24,17 @@ describe('buildPointCloudData', () => { expect([...data.positions]).toEqual([1, 0, 0, 2, 0, 0]) expect(data.colors ? [...data.colors] : null).toEqual([0, 1, 0, 0, 0, 1]) }) + + test('renders bounded inline capture points', () => { + const data = buildPointCloudPayloadData( + { + coordinateSystem: 'arkit-world', + positions: [0, 0, 0, 1, 0, 0, 2, 0, 0], + }, + 2, + ) + + expect([...data.positions]).toEqual([1, 0, 0, 2, 0, 0]) + expect(data.colors).toBeNull() + }) }) diff --git a/packages/capture-viewer/src/stream-rendering.test.ts b/packages/capture-viewer/src/stream-rendering.test.ts index 584ff88922..20ee43e714 100644 --- a/packages/capture-viewer/src/stream-rendering.test.ts +++ b/packages/capture-viewer/src/stream-rendering.test.ts @@ -21,6 +21,18 @@ describe('isCaptureStreamRenderable', () => { artifact: { id: 'points', mediaType: 'application/ply', uri: '/points.ply' }, }), ).toBe(true) + expect( + isCaptureStreamRenderable({ + id: 'inline-points', + kind: 'point-cloud', + role: 'pointCloud', + availability: 'ready', + inline: { + coordinateSystem: 'arkit-world', + positions: [0, 0, 0, 1, 1, 1], + }, + }), + ).toBe(true) }) test('allows a host renderer to claim an otherwise unknown stream', () => { diff --git a/packages/capture-viewer/src/stream-rendering.ts b/packages/capture-viewer/src/stream-rendering.ts index d4b1203a11..9a02e8859b 100644 --- a/packages/capture-viewer/src/stream-rendering.ts +++ b/packages/capture-viewer/src/stream-rendering.ts @@ -3,6 +3,7 @@ import { type CaptureStreamDescriptor, captureLayerKey, DeviceMotionTrajectorySchema, + PointCloudPayloadSchema, } from '@pascal-app/capture-protocol' const GLB_MEDIA_TYPES = new Set(['model/gltf-binary', 'model/gltf+json']) @@ -26,7 +27,11 @@ export function isCaptureStreamRenderable( ) } if (layerKey === 'pointCloud') { - return stream.availability === 'live' || isCapturePointCloudArtifact(stream.artifact) + return ( + stream.availability === 'live' || + isCapturePointCloudArtifact(stream.artifact) || + PointCloudPayloadSchema.safeParse(stream.inline).success + ) } return false } diff --git a/packages/editor/src/components/ui/panels/reference-panel.tsx b/packages/editor/src/components/ui/panels/reference-panel.tsx index 069a51288a..86da5ccd89 100644 --- a/packages/editor/src/components/ui/panels/reference-panel.tsx +++ b/packages/editor/src/components/ui/panels/reference-panel.tsx @@ -13,6 +13,7 @@ import { EyeOff, LocateFixed, Lock, + Move, RotateCcw, Ruler, Trash2, @@ -144,6 +145,12 @@ export function ReferencePanel() { guideEmitter.emit('guide:cancel-reference-scale') }, []) + const handleMoveScan = useCallback(() => { + if (node?.type !== 'scan') return + useEditor.getState().setMovingNode(node as never) + setSelectedReferenceId(null) + }, [node, setSelectedReferenceId]) + useEffect(() => { if (node?.type !== 'guide' || !node.url.startsWith('asset://')) { setIsAssetMissing(false) @@ -172,7 +179,7 @@ export function ReferencePanel() { return ( {!isScan && ( @@ -329,6 +336,29 @@ export function ReferencePanel() { )} + {isScan && ( + + + } + label="Move" + onClick={handleMoveScan} + /> + + ) : ( + + ) + } + label={node.visible === false ? 'Show' : 'Hide'} + onClick={() => handleUpdate({ visible: node.visible === false })} + /> + + + )} + void }) { const [isEditing, setIsEditing] = useState(false) + const [isExpanded, setIsExpanded] = useState(true) + const updateNode = useScene((state) => state.updateNode) + const selectedReferenceId = useEditor((state) => state.selectedReferenceId) + const isCapture = refNode.type === 'scan' + const isVisible = refNode.visible !== false + useSyncExternalStore( + editorHostTreeChildrenRegistry.subscribe, + editorHostTreeChildrenRegistry.getSnapshot, + editorHostTreeChildrenRegistry.getSnapshot, + ) + const hostChildren = isCapture + ? editorHostTreeChildrenRegistry.childrenForKind(refNode.type) + : undefined + const hasHostChildren = Boolean(hostChildren?.hasChildren(refNode)) + const HostChildren = hasHostChildren ? hostChildren?.component : undefined + const handleSelect = () => { setSelectedReferenceId(refNode.id) + useViewer.getState().setSelection({ selectedIds: [], zoneId: null }) } const handleDoubleClick = () => { @@ -359,53 +380,98 @@ const ReferenceItem = memo(function ReferenceItem({ } return ( -
+
-
+ onClick={handleSelect} + onDoubleClick={handleDoubleClick} + > +
+
-
- {refNode.type === 'scan' ? ( - Scan - ) : ( - Guide { + event.stopPropagation() + if (hasHostChildren) setIsExpanded((expanded) => !expanded) + }} + type="button" + > + {hasHostChildren ? ( + + ) : null} + + ) : null} + +
+ {isCapture ? ( + Capture + ) : ( + Guide + )} + setIsEditing(true)} + onStopEditing={() => setIsEditing(false)} /> - )} - setIsEditing(true)} - onStopEditing={() => setIsEditing(false)} - /> -
+
- + {isCapture ? ( + + ) : null} + +
+ {isExpanded && HostChildren ? ( + + ) : null}
) }) @@ -1332,7 +1398,10 @@ const ContentSection = memo(function ContentSection() { if (!selectedLevelId) return [] const lvl = s.nodes[selectedLevelId] as LevelNode | undefined if (!lvl) return [] - return lvl.children.filter((childId) => s.nodes[childId]?.type !== 'zone') + return lvl.children.filter((childId) => { + const type = s.nodes[childId]?.type + return type !== 'zone' && type !== 'scan' + }) }), ) diff --git a/packages/nodes/src/scan/definition.ts b/packages/nodes/src/scan/definition.ts index 5b7f718cab..ba13caf293 100644 --- a/packages/nodes/src/scan/definition.ts +++ b/packages/nodes/src/scan/definition.ts @@ -23,6 +23,9 @@ export const scanDefinition: NodeDefinition = { capabilities: { selectable: { hitVolume: 'bbox' }, + movable: { axes: ['x', 'y', 'z'], gridSnap: true }, + rotatable: { axes: ['y'], snapAngles: [Math.PI / 4] }, + scalable: { axes: ['x', 'y', 'z'], min: 0.01, max: 10 }, duplicable: false, deletable: true, // Scans carry user-uploaded imagery — cataloging them as diff --git a/packages/nodes/src/scan/parametrics.ts b/packages/nodes/src/scan/parametrics.ts index 0852530d8f..6e2f389aa2 100644 --- a/packages/nodes/src/scan/parametrics.ts +++ b/packages/nodes/src/scan/parametrics.ts @@ -1,5 +1,17 @@ import type { ParametricDescriptor, ScanNode } from '@pascal-app/core' export const scanParametrics: ParametricDescriptor = { - groups: [], + groups: [ + { + label: 'Transform', + fields: [ + { key: 'position', kind: 'vec3' }, + { key: 'scale', kind: 'number', min: 0.01, max: 10, step: 0.1 }, + ], + }, + { + label: 'Appearance', + fields: [{ key: 'opacity', kind: 'number', unit: '%', min: 0, max: 100, step: 1 }], + }, + ], } From e636d1c9d03b4639b8aff87225df9d511aaa689a Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Thu, 20 Aug 2026 10:50:45 -0400 Subject: [PATCH 07/12] feat(capture): render color surface meshes --- packages/capture-protocol/src/index.ts | 3 + packages/capture-protocol/src/schema.test.ts | 65 +++++++++- packages/capture-protocol/src/schema.ts | 120 ++++++++++++++++++ .../capture-viewer/src/capture-runtime.tsx | 3 + packages/capture-viewer/src/index.ts | 5 + .../src/layers/surface-mesh-layer.tsx | 96 ++++++++++++++ .../src/stream-rendering.test.ts | 27 ++++ .../capture-viewer/src/stream-rendering.ts | 2 + .../src/surface-mesh-layer.test.ts | 51 ++++++++ wiki/architecture/capture-runtime.md | 11 +- 10 files changed, 378 insertions(+), 5 deletions(-) create mode 100644 packages/capture-viewer/src/layers/surface-mesh-layer.tsx create mode 100644 packages/capture-viewer/src/surface-mesh-layer.test.ts diff --git a/packages/capture-protocol/src/index.ts b/packages/capture-protocol/src/index.ts index 4f1226444a..097ae99055 100644 --- a/packages/capture-protocol/src/index.ts +++ b/packages/capture-protocol/src/index.ts @@ -1,6 +1,7 @@ export { ArkitDeviceMotionTrajectorySchema, ArkitPointCloudPayloadSchema, + ArkitSurfaceMeshPayloadSchema, type CaptureArtifactReference, CaptureArtifactReferenceSchema, type CaptureClock, @@ -28,6 +29,8 @@ export { normalizeCaptureSessionManifest, type PointCloudPayload, PointCloudPayloadSchema, + type SurfaceMeshPayload, + SurfaceMeshPayloadSchema, } from './schema' export { type CaptureArtifactResolution, diff --git a/packages/capture-protocol/src/schema.test.ts b/packages/capture-protocol/src/schema.test.ts index 55d3054758..4d2c471f67 100644 --- a/packages/capture-protocol/src/schema.test.ts +++ b/packages/capture-protocol/src/schema.test.ts @@ -36,15 +36,43 @@ describe('capture manifests', () => { positions: [0, 0, 0, 1, 1, 1], }, }, + surfaceMesh: { + kind: 'surface-mesh', + mesh: { + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 3, + faceCount: 1, + boundsMin: [0, 0, 0], + boundsMax: [1, 1, 0], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: 'AAAAAAAAAAAAAAAAAAAAAAAA', + colors: '////////////', + indices: 'AAABAAIA', + }, + }, }, }) - expect(descriptor.streams.map(captureLayerKey)).toEqual(['model', 'deviceMotion', 'pointCloud']) + expect(descriptor.streams.map(captureLayerKey)).toEqual([ + 'model', + 'deviceMotion', + 'pointCloud', + 'surfaceMesh', + ]) expect(descriptor.streams[0]?.artifact?.uri).toBe('https://cdn.pascal.app/room.usdz') expect(descriptor.streams[2]?.inline).toMatchObject({ coordinateSystem: 'arkit-world', positions: [0, 0, 0, 1, 1, 1], }) + expect(descriptor.streams[3]?.inline).toMatchObject({ + appearance: 'camera-vertex-color', + faceCount: 1, + }) }) test('keeps unknown v2 stream kinds without a protocol release', () => { @@ -86,6 +114,41 @@ describe('capture manifests', () => { ).toThrow() }) + test('rejects oversized or structurally inconsistent surface meshes', () => { + const surfaceMesh = { + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 3, + faceCount: 1, + boundsMin: [0, 0, 0], + boundsMax: [1, 1, 0], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: 'AAAAAAAAAAAAAAAAAAAAAAAA', + colors: '////////////', + indices: 'AAABAAIA', + } + const manifest = (mesh: unknown) => ({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: { surfaceMesh: { kind: 'surface-mesh', mesh } }, + }) + + expect(() => + normalizeCaptureSessionManifest(manifest({ ...surfaceMesh, faceCount: 6_001 })), + ).toThrow() + expect(() => + normalizeCaptureSessionManifest(manifest({ ...surfaceMesh, positions: 'AAAA' })), + ).toThrow('decoded bytes') + expect(() => + normalizeCaptureSessionManifest(manifest({ ...surfaceMesh, indices: 'AAABAP//' })), + ).toThrow('existing vertex') + }) + test('rejects duplicate stream IDs and backwards time ranges', () => { expect(() => normalizeCaptureSessionManifest({ diff --git a/packages/capture-protocol/src/schema.ts b/packages/capture-protocol/src/schema.ts index 73794afdc1..a23ec73106 100644 --- a/packages/capture-protocol/src/schema.ts +++ b/packages/capture-protocol/src/schema.ts @@ -51,6 +51,70 @@ export const ArkitPointCloudPayloadSchema = PointCloudPayloadSchema.safeExtend({ coordinateSystem: z.literal('arkit-world'), }) +const MAX_SURFACE_MESH_VERTICES = 65_535 +const MAX_SURFACE_MESH_FACES = 6_000 + +export const SurfaceMeshPayloadSchema = z + .object({ + version: z.literal(1), + coordinateSystem: z.string().min(1), + representation: z.literal('quantized-indexed-triangle-mesh'), + appearance: z.literal('camera-vertex-color'), + vertexCount: z.number().int().positive().max(MAX_SURFACE_MESH_VERTICES), + faceCount: z.number().int().positive().max(MAX_SURFACE_MESH_FACES), + boundsMin: z.array(z.number()).length(3), + boundsMax: z.array(z.number()).length(3), + positionEncoding: z.literal('uint16x3-base64-little-endian'), + colorEncoding: z.literal('uint8x3-base64-srgb'), + indexEncoding: z.literal('uint16x3-base64-little-endian'), + positions: z.string().min(1).max(524_280), + colors: z.string().min(1).max(262_140), + indices: z.string().min(1).max(48_000), + }) + .superRefine((payload, context) => { + if (payload.vertexCount > payload.faceCount * 3) { + context.addIssue({ + code: 'custom', + message: 'Surface meshes cannot contain more than three vertices per face.', + path: ['vertexCount'], + }) + } + for (let axis = 0; axis < 3; axis += 1) { + if ((payload.boundsMax[axis] ?? 0) < (payload.boundsMin[axis] ?? 0)) { + context.addIssue({ + code: 'custom', + message: 'Surface-mesh maximum bounds must not be below minimum bounds.', + path: ['boundsMax', axis], + }) + } + } + + const positionBytes = decodeBase64(payload.positions) + const colorBytes = decodeBase64(payload.colors) + const indexBytes = decodeBase64(payload.indices) + validateSurfaceMeshByteLength(positionBytes, payload.vertexCount * 3 * 2, 'positions', context) + validateSurfaceMeshByteLength(colorBytes, payload.vertexCount * 3, 'colors', context) + validateSurfaceMeshByteLength(indexBytes, payload.faceCount * 3 * 2, 'indices', context) + + if (indexBytes?.byteLength === payload.faceCount * 3 * 2) { + const indices = new DataView(indexBytes.buffer, indexBytes.byteOffset, indexBytes.byteLength) + for (let offset = 0; offset < indexBytes.byteLength; offset += 2) { + if (indices.getUint16(offset, true) >= payload.vertexCount) { + context.addIssue({ + code: 'custom', + message: 'Surface-mesh indices must reference an existing vertex.', + path: ['indices'], + }) + break + } + } + } + }) + +export const ArkitSurfaceMeshPayloadSchema = SurfaceMeshPayloadSchema.safeExtend({ + coordinateSystem: z.literal('arkit-world'), +}) + export const CaptureTimeRangeSchema = z .object({ start: z.number().nonnegative(), @@ -121,6 +185,12 @@ export const CaptureSessionManifestV1Schema = z.object({ points: ArkitPointCloudPayloadSchema, }) .optional(), + surfaceMesh: z + .object({ + kind: z.literal('surface-mesh'), + mesh: ArkitSurfaceMeshPayloadSchema, + }) + .optional(), }), }) @@ -168,6 +238,7 @@ export type CaptureSessionManifestV2 = z.infer export type DeviceMotionTrajectoryPayload = z.infer export type PointCloudPayload = z.infer +export type SurfaceMeshPayload = z.infer export function normalizeCaptureSessionManifest(value: unknown): CaptureSessionDescriptor { const manifest = CaptureSessionManifestSchema.parse(value) @@ -205,6 +276,15 @@ export function normalizeCaptureSessionManifest(value: unknown): CaptureSessionD inline: manifest.streams.pointCloud.points, }) } + if (manifest.streams.surfaceMesh) { + streams.push({ + id: 'surface-mesh', + kind: manifest.streams.surfaceMesh.kind, + role: 'surfaceMesh', + availability: 'ready', + inline: manifest.streams.surfaceMesh.mesh, + }) + } return CaptureSessionDescriptorSchema.parse({ schemaVersion: manifest.schemaVersion, @@ -222,6 +302,7 @@ export function captureLayerKey(stream: CaptureStreamDescriptor): string { if (stream.kind === 'room-model') return 'model' if (stream.kind === 'device-motion') return 'deviceMotion' if (stream.kind === 'point-cloud') return 'pointCloud' + if (stream.kind === 'surface-mesh') return 'surfaceMesh' if (stream.kind === 'gaussian-splat') return 'splat' return stream.kind } @@ -231,6 +312,7 @@ export function captureStreamLabel(stream: CaptureStreamDescriptor): string { if (key === 'model') return '3D model' if (key === 'deviceMotion') return 'Device motion' if (key === 'pointCloud') return 'Point cloud' + if (key === 'surfaceMesh') return 'Surface mesh' if (key === 'splat') return 'Gaussian splat' return key .replace(/([a-z])([A-Z])/g, '$1 $2') @@ -238,6 +320,44 @@ export function captureStreamLabel(stream: CaptureStreamDescriptor): string { .replace(/^./, (value) => value.toUpperCase()) } +function validateSurfaceMeshByteLength( + bytes: Uint8Array | null, + expectedLength: number, + path: 'colors' | 'indices' | 'positions', + context: { addIssue(issue: { code: 'custom'; message: string; path: string[] }): void }, +): void { + if (bytes?.byteLength === expectedLength) return + context.addIssue({ + code: 'custom', + message: `Surface-mesh ${path} must contain exactly ${expectedLength} decoded bytes.`, + path: [path], + }) +} + +function decodeBase64(value: string): Uint8Array | null { + if ( + value.length % 4 !== 0 || + !/^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?$/.test(value) + ) { + return null + } + const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + const padding = value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0 + const output = new Uint8Array((value.length / 4) * 3 - padding) + let outputIndex = 0 + for (let index = 0; index < value.length; index += 4) { + const a = alphabet.indexOf(value[index] ?? '') + const b = alphabet.indexOf(value[index + 1] ?? '') + const c = value[index + 2] === '=' ? 0 : alphabet.indexOf(value[index + 2] ?? '') + const d = value[index + 3] === '=' ? 0 : alphabet.indexOf(value[index + 3] ?? '') + const bits = a * 262_144 + b * 4096 + c * 64 + d + if (outputIndex < output.length) output[outputIndex++] = Math.floor(bits / 65_536) % 256 + if (outputIndex < output.length) output[outputIndex++] = Math.floor(bits / 256) % 256 + if (outputIndex < output.length) output[outputIndex++] = bits % 256 + } + return output +} + function validateUniqueSessionIds( value: { clocks: Array<{ id: string }> diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index e99a6c5412..0c3129fd64 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -22,6 +22,7 @@ import { resolveCaptureFrameMatrix } from './frame' import { CaptureDeviceMotionLayer } from './layers/device-motion-layer' import { CapturePointCloudLayer } from './layers/point-cloud-layer' import { CaptureRoomModel } from './layers/room-model-layer' +import { CaptureSurfaceMeshLayer } from './layers/surface-mesh-layer' import { useCaptureSource } from './source-state' import { captureModelFormat, @@ -230,6 +231,8 @@ export function CaptureStreamLayer({ packets={stream.availability === 'live' ? packets : []} /> ) + } else if (layerKey === 'surfaceMesh') { + content = } if (!(content && frameMatrix)) return content return ( diff --git a/packages/capture-viewer/src/index.ts b/packages/capture-viewer/src/index.ts index 926f6a106f..7d63e87c0e 100644 --- a/packages/capture-viewer/src/index.ts +++ b/packages/capture-viewer/src/index.ts @@ -17,6 +17,11 @@ export { type PointCloudData, } from './layers/point-cloud-layer' export { CaptureRoomModel } from './layers/room-model-layer' +export { + buildSurfaceMeshData, + CaptureSurfaceMeshLayer, + type SurfaceMeshData, +} from './layers/surface-mesh-layer' export { appendCapturePacket, type CaptureSourceState, diff --git a/packages/capture-viewer/src/layers/surface-mesh-layer.tsx b/packages/capture-viewer/src/layers/surface-mesh-layer.tsx new file mode 100644 index 0000000000..f8cf463608 --- /dev/null +++ b/packages/capture-viewer/src/layers/surface-mesh-layer.tsx @@ -0,0 +1,96 @@ +'use client' + +import { SurfaceMeshPayloadSchema } from '@pascal-app/capture-protocol' +import { useEffect, useMemo } from 'react' +import { BufferGeometry, DoubleSide, Float32BufferAttribute, Uint16BufferAttribute } from 'three' + +export type SurfaceMeshData = { + colors: Float32Array + indices: Uint16Array + positions: Float32Array +} + +export function CaptureSurfaceMeshLayer({ inline }: { inline: unknown }) { + const data = useMemo(() => buildSurfaceMeshData(inline), [inline]) + const geometry = useMemo(() => { + if (!data) return null + const next = new BufferGeometry() + next.setAttribute('position', new Float32BufferAttribute(data.positions, 3)) + next.setAttribute('color', new Float32BufferAttribute(data.colors, 3)) + next.setIndex(new Uint16BufferAttribute(data.indices, 1)) + next.computeVertexNormals() + next.computeBoundingSphere() + return next + }, [data]) + useEffect(() => () => geometry?.dispose(), [geometry]) + if (!geometry) return null + + return ( + + + + ) +} + +export function buildSurfaceMeshData(value: unknown): SurfaceMeshData | null { + const parsed = SurfaceMeshPayloadSchema.safeParse(value) + if (!parsed.success) return null + const payload = parsed.data + const positionBytes = decodeBase64(payload.positions) + const colorBytes = decodeBase64(payload.colors) + const indexBytes = decodeBase64(payload.indices) + if ( + positionBytes.byteLength !== payload.vertexCount * 3 * 2 || + colorBytes.byteLength !== payload.vertexCount * 3 || + indexBytes.byteLength !== payload.faceCount * 3 * 2 + ) { + return null + } + + const positions = new Float32Array(payload.vertexCount * 3) + const colors = new Float32Array(payload.vertexCount * 3) + const indices = new Uint16Array(payload.faceCount * 3) + const positionView = new DataView( + positionBytes.buffer, + positionBytes.byteOffset, + positionBytes.byteLength, + ) + const indexView = new DataView(indexBytes.buffer, indexBytes.byteOffset, indexBytes.byteLength) + for (let index = 0; index < payload.vertexCount; index += 1) { + for (let axis = 0; axis < 3; axis += 1) { + const offset = index * 3 + axis + const minimum = payload.boundsMin[axis] ?? 0 + const maximum = payload.boundsMax[axis] ?? minimum + const quantized = positionView.getUint16(offset * 2, true) + positions[offset] = minimum + (quantized / 65_535) * (maximum - minimum) + colors[offset] = (colorBytes[offset] ?? 0) / 255 + } + } + for (let index = 0; index < indices.length; index += 1) { + const vertexIndex = indexView.getUint16(index * 2, true) + if (vertexIndex >= payload.vertexCount) return null + indices[index] = vertexIndex + } + return { colors, indices, positions } +} + +function decodeBase64(value: string): Uint8Array { + const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + const clean = value.replace(/\s/g, '') + const padding = clean.endsWith('==') ? 2 : clean.endsWith('=') ? 1 : 0 + const outputLength = Math.floor((clean.length * 3) / 4) - padding + const output = new Uint8Array(Math.max(0, outputLength)) + let outputIndex = 0 + for (let index = 0; index < clean.length; index += 4) { + const a = alphabet.indexOf(clean[index] ?? '') + const b = alphabet.indexOf(clean[index + 1] ?? '') + const c = clean[index + 2] === '=' ? 0 : alphabet.indexOf(clean[index + 2] ?? '') + const d = clean[index + 3] === '=' ? 0 : alphabet.indexOf(clean[index + 3] ?? '') + if (a < 0 || b < 0 || c < 0 || d < 0) return new Uint8Array() + const bits = (a << 18) | (b << 12) | (c << 6) | d + if (outputIndex < output.length) output[outputIndex++] = (bits >> 16) & 0xff + if (outputIndex < output.length) output[outputIndex++] = (bits >> 8) & 0xff + if (outputIndex < output.length) output[outputIndex++] = bits & 0xff + } + return output +} diff --git a/packages/capture-viewer/src/stream-rendering.test.ts b/packages/capture-viewer/src/stream-rendering.test.ts index 20ee43e714..48d00c02bd 100644 --- a/packages/capture-viewer/src/stream-rendering.test.ts +++ b/packages/capture-viewer/src/stream-rendering.test.ts @@ -43,4 +43,31 @@ describe('isCaptureStreamRenderable', () => { ), ).toBe(true) }) + + test('renders a valid inline color surface mesh', () => { + expect( + isCaptureStreamRenderable({ + id: 'surface-mesh', + kind: 'surface-mesh', + role: 'surfaceMesh', + availability: 'ready', + inline: { + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 3, + faceCount: 1, + boundsMin: [0, 0, 0], + boundsMax: [1, 1, 0], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: 'AAAAAAAAAAAAAAAAAAAAAAAA', + colors: '////////////', + indices: 'AAABAAIA', + }, + }), + ).toBe(true) + }) }) diff --git a/packages/capture-viewer/src/stream-rendering.ts b/packages/capture-viewer/src/stream-rendering.ts index 9a02e8859b..e5e773d8cb 100644 --- a/packages/capture-viewer/src/stream-rendering.ts +++ b/packages/capture-viewer/src/stream-rendering.ts @@ -4,6 +4,7 @@ import { captureLayerKey, DeviceMotionTrajectorySchema, PointCloudPayloadSchema, + SurfaceMeshPayloadSchema, } from '@pascal-app/capture-protocol' const GLB_MEDIA_TYPES = new Set(['model/gltf-binary', 'model/gltf+json']) @@ -33,6 +34,7 @@ export function isCaptureStreamRenderable( PointCloudPayloadSchema.safeParse(stream.inline).success ) } + if (layerKey === 'surfaceMesh') return SurfaceMeshPayloadSchema.safeParse(stream.inline).success return false } diff --git a/packages/capture-viewer/src/surface-mesh-layer.test.ts b/packages/capture-viewer/src/surface-mesh-layer.test.ts new file mode 100644 index 0000000000..44a408c9f1 --- /dev/null +++ b/packages/capture-viewer/src/surface-mesh-layer.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, test } from 'bun:test' +import { buildSurfaceMeshData } from './layers/surface-mesh-layer' + +describe('surface mesh layer', () => { + test('decodes quantized positions, vertex colors, and triangle indices', () => { + const positions = new Uint8Array([0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0]) + const colors = new Uint8Array([255, 0, 0, 0, 255, 0, 0, 0, 255]) + const indices = new Uint8Array([0, 0, 1, 0, 2, 0]) + const data = buildSurfaceMeshData({ + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 3, + faceCount: 1, + boundsMin: [0, 0, 0], + boundsMax: [2, 2, 0], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: Buffer.from(positions).toString('base64'), + colors: Buffer.from(colors).toString('base64'), + indices: Buffer.from(indices).toString('base64'), + }) + + expect(Array.from(data?.positions ?? [])).toEqual([0, 0, 0, 2, 0, 0, 0, 2, 0]) + expect(Array.from(data?.indices ?? [])).toEqual([0, 1, 2]) + expect(Array.from(data?.colors ?? [])).toEqual([1, 0, 0, 0, 1, 0, 0, 0, 1]) + }) + + test('rejects malformed buffers and out-of-range indices', () => { + expect( + buildSurfaceMeshData({ + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 1, + faceCount: 1, + boundsMin: [0, 0, 0], + boundsMax: [1, 1, 1], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: 'AA==', + colors: 'AAAA', + indices: 'AAABAAIA', + }), + ).toBeNull() + }) +}) diff --git a/wiki/architecture/capture-runtime.md b/wiki/architecture/capture-runtime.md index 127e0ff94d..8df4a6b66b 100644 --- a/wiki/architecture/capture-runtime.md +++ b/wiki/architecture/capture-runtime.md @@ -11,7 +11,7 @@ scene graph. - `@pascal-app/capture-viewer` mounts inside `Viewer` through its existing children slot. It resolves `scan.captureSession`, portals layers into that scan node's registered group, honors per-layer visibility, composes declared local-to-parent coordinate frames into session space, and supplies - reference model, device-motion, and point-cloud renderers. + reference model, device-motion, point-cloud, and compact color-surface renderers. - `@pascal-app/core` stores only the scene anchor: session locator, optional current mesh URL, placement, opacity, and an extensible visibility map. Raw samples and artifact inventories never enter scene JSON. @@ -36,9 +36,12 @@ artifact and privacy policy before it can use the same runtime safely. ## Stream extension Manifest v2 streams use stable IDs plus open `kind` and `role` strings. Known roles currently map to -`model`, `deviceMotion`, and `pointCloud`. Unknown streams remain available to hosts, which can add a -renderer keyed by role or kind without changing the scene schema. A splat adapter should remain a -separate composited renderer while still consuming the same source and visibility contract. +`model`, `deviceMotion`, `pointCloud`, and `surfaceMesh`. The reference surface renderer accepts the +bounded quantized inline preview emitted by Capture; a future UV-textured or server-reconstructed +mesh can be another artifact-backed stream without changing `ScanNode`. Unknown streams remain +available to hosts, which can add a renderer keyed by role or kind without changing the scene +schema. A splat adapter should remain a separate composited renderer while still consuming the same +source and visibility contract. ## Compatibility From a6ea6031ccec6e27ac61cf4d0f3713469bbb5253 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Fri, 21 Aug 2026 15:51:27 -0400 Subject: [PATCH 08/12] feat(capture): add runtime recovery observability hooks --- packages/capture-protocol/src/schema.test.ts | 48 +++++++++++++++++ packages/capture-protocol/src/schema.ts | 8 +-- packages/capture-viewer/README.md | 5 ++ .../capture-viewer/src/capture-runtime.tsx | 53 ++++++++++++++++--- packages/capture-viewer/src/index.ts | 1 + packages/capture-viewer/src/source-state.ts | 23 +++++--- 6 files changed, 119 insertions(+), 19 deletions(-) diff --git a/packages/capture-protocol/src/schema.test.ts b/packages/capture-protocol/src/schema.test.ts index 4d2c471f67..bd44354b74 100644 --- a/packages/capture-protocol/src/schema.test.ts +++ b/packages/capture-protocol/src/schema.test.ts @@ -149,6 +149,54 @@ describe('capture manifests', () => { ).toThrow('existing vertex') }) + test('rejects non-finite capture geometry', () => { + expect(() => + normalizeCaptureSessionManifest({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: { + pointCloud: { + kind: 'point-cloud', + points: { + coordinateSystem: 'arkit-world', + positions: [0, 0, Number.POSITIVE_INFINITY], + }, + }, + }, + }), + ).toThrow() + + expect(() => + normalizeCaptureSessionManifest({ + schemaVersion: 1, + sessionId: 'capture_123', + projectId: 'project_123', + streams: { + surfaceMesh: { + kind: 'surface-mesh', + mesh: { + version: 1, + coordinateSystem: 'arkit-world', + representation: 'quantized-indexed-triangle-mesh', + appearance: 'camera-vertex-color', + vertexCount: 3, + faceCount: 1, + boundsMin: [0, 0, Number.NaN], + boundsMax: [1, 1, 0], + positionEncoding: 'uint16x3-base64-little-endian', + colorEncoding: 'uint8x3-base64-srgb', + indexEncoding: 'uint16x3-base64-little-endian', + positions: 'AAAAAAAAAAAAAAAAAAAAAAAA', + colors: '////////////', + indices: 'AAABAAIA', + }, + }, + }, + }), + ).toThrow() + }) + test('rejects duplicate stream IDs and backwards time ranges', () => { expect(() => normalizeCaptureSessionManifest({ diff --git a/packages/capture-protocol/src/schema.ts b/packages/capture-protocol/src/schema.ts index a23ec73106..7ff16ea261 100644 --- a/packages/capture-protocol/src/schema.ts +++ b/packages/capture-protocol/src/schema.ts @@ -27,8 +27,8 @@ export const ArkitDeviceMotionTrajectorySchema = DeviceMotionTrajectorySchema.ex export const PointCloudPayloadSchema = z .object({ coordinateSystem: z.string().min(1), - positions: z.array(z.number()).min(3), - colors: z.array(z.number()).optional(), + positions: z.array(z.number().finite()).min(3), + colors: z.array(z.number().finite()).optional(), }) .superRefine((payload, context) => { if (payload.positions.length % 3 !== 0) { @@ -62,8 +62,8 @@ export const SurfaceMeshPayloadSchema = z appearance: z.literal('camera-vertex-color'), vertexCount: z.number().int().positive().max(MAX_SURFACE_MESH_VERTICES), faceCount: z.number().int().positive().max(MAX_SURFACE_MESH_FACES), - boundsMin: z.array(z.number()).length(3), - boundsMax: z.array(z.number()).length(3), + boundsMin: z.array(z.number().finite()).length(3), + boundsMax: z.array(z.number().finite()).length(3), positionEncoding: z.literal('uint16x3-base64-little-endian'), colorEncoding: z.literal('uint8x3-base64-srgb'), indexEncoding: z.literal('uint16x3-base64-little-endian'), diff --git a/packages/capture-viewer/README.md b/packages/capture-viewer/README.md index 44cbfbaea8..d2ab14001a 100644 --- a/packages/capture-viewer/README.md +++ b/packages/capture-viewer/README.md @@ -9,6 +9,7 @@ and reference renderers for RoomPlan models, device trajectories, and PLY/live p ```tsx reportCaptureError(error, context)} resolveSource={(locator) => createHttpCaptureSource(locator, { credentials: 'include' }) } @@ -19,3 +20,7 @@ and reference renderers for RoomPlan models, device trajectories, and PLY/live p Unknown streams remain in the descriptor and can be rendered by passing a custom renderer keyed by stream role or kind. A live transport implements `CaptureSource.subscribe()`; no particular WebSocket, WebRTC, or collaboration backend is required by this package. + +`CaptureRuntime` keeps telemetry host-neutral: pass `onError` to report source or per-stream +failures in the host. `useCaptureSource()` exposes `retry()` so host controls can recover from a +transient manifest or transport failure without remounting the viewer. diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index 0c3129fd64..ba90fc5b3f 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -44,16 +44,34 @@ export type CaptureStreamRendererProps = { export type CaptureStreamRenderer = ComponentType +export type CaptureRuntimeErrorContext = + | { + phase: 'source' + scanId: ScanNode['id'] + sessionId: string + } + | { + layerKey: string + phase: 'stream' + scanId: ScanNode['id'] + sessionId: string + streamId: string + streamKind: string + } + export type CaptureRuntimeProps = { maxPacketsPerStream?: number + onError?: (error: Error, context: CaptureRuntimeErrorContext) => void renderers?: Readonly> resolveSource: CaptureSourceResolver } const EMPTY_RENDERERS: Readonly> = {} +type CaptureSessionScan = ScanNode & { captureSession: CaptureSessionLocator } export function CaptureRuntime({ maxPacketsPerStream = 32, + onError, renderers = EMPTY_RENDERERS, resolveSource, }: CaptureRuntimeProps) { @@ -61,7 +79,7 @@ export function CaptureRuntime({ const scans = useMemo( () => Object.values(nodes).filter( - (node): node is ScanNode => node.type === 'scan' && node.captureSession !== null, + (node): node is CaptureSessionScan => node.type === 'scan' && node.captureSession !== null, ), [nodes], ) @@ -72,6 +90,7 @@ export function CaptureRuntime({ void renderers: Readonly> resolveSource: CaptureSourceResolver - scan: ScanNode + scan: CaptureSessionScan }) { const [target, setTarget] = useState(null) const handlers = useNodeEvents(scan, 'scan') - const sourceState = useCaptureSource( - scan.captureSession as CaptureSessionLocator, - resolveSource, - { maxPacketsPerStream }, - ) + const sourceState = useCaptureSource(scan.captureSession, resolveSource, { + maxPacketsPerStream, + }) + + useEffect(() => { + if (!sourceState.error) return + onError?.(sourceState.error, { + phase: 'source', + scanId: scan.id, + sessionId: scan.captureSession.sessionId, + }) + }, [onError, scan.captureSession.sessionId, scan.id, sourceState.error]) useFrame(() => { const nextTarget = sceneRegistry.nodes.get(scan.id) ?? null @@ -121,7 +149,18 @@ function CaptureSessionPortal({ } key={renderKey} + onError={(error) => + onError?.(error, { + layerKey, + phase: 'stream', + scanId: scan.id, + sessionId: scan.captureSession.sessionId, + streamId: stream.id, + streamKind: stream.kind, + }) + } resetKey={`${renderKey}:${sourceState.descriptorVersion}`} + scope={`capture:${layerKey}`} > > + retry: () => void source: CaptureSource | null streamEpochs: Readonly> } +type CaptureSourceSnapshot = Omit + export type UseCaptureSourceOptions = { maxPacketsPerStream?: number subscribe?: boolean @@ -31,7 +34,8 @@ export function useCaptureSource( options: UseCaptureSourceOptions = {}, ): CaptureSourceState { const { maxPacketsPerStream = 32, subscribe = true } = options - const [state, setState] = useState({ + const [retryVersion, setRetryVersion] = useState(0) + const [state, setState] = useState({ descriptor: null, descriptorVersion: 0, error: null, @@ -58,7 +62,7 @@ export function useCaptureSource( setState({ descriptor: null, - descriptorVersion: 0, + descriptorVersion: retryVersion, error: null, loading: true, packets: EMPTY_PACKETS, @@ -69,24 +73,27 @@ export function useCaptureSource( locator, resolveSource, abort.signal, + retryVersion, maxPacketsPerStream, subscribe, setState, ) return () => abort.abort() - }, [locator, maxPacketsPerStream, resolveSource, subscribe]) + }, [locator, maxPacketsPerStream, resolveSource, retryVersion, subscribe]) - return state + const retry = useCallback(() => setRetryVersion((current) => current + 1), []) + return { ...state, retry } } async function consumeCaptureSource( locator: CaptureSessionLocator, resolveSource: CaptureSourceResolver, signal: AbortSignal, + descriptorVersion: number, maxPacketsPerStream: number, subscribe: boolean, setState: ( - update: CaptureSourceState | ((current: CaptureSourceState) => CaptureSourceState), + update: CaptureSourceSnapshot | ((current: CaptureSourceSnapshot) => CaptureSourceSnapshot), ) => void, ): Promise { try { @@ -95,7 +102,7 @@ async function consumeCaptureSource( if (signal.aborted) return setState({ descriptor, - descriptorVersion: 0, + descriptorVersion, error: null, loading: false, packets: EMPTY_PACKETS, @@ -158,7 +165,7 @@ async function consumeCaptureSource( if (signal.aborted) return setState({ descriptor: null, - descriptorVersion: 0, + descriptorVersion, error: cause instanceof Error ? cause : new Error('Could not load capture session.'), loading: false, packets: EMPTY_PACKETS, From fc417dffb4975d8a9126182c03054289fe3cbfb5 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Fri, 21 Aug 2026 16:41:14 -0400 Subject: [PATCH 09/12] fix(capture): recover failed runtime streams --- packages/capture-protocol/README.md | 4 ++ packages/capture-protocol/package.json | 6 ++- packages/capture-viewer/README.md | 5 ++- .../capture-viewer/src/capture-runtime.tsx | 42 ++++++++++++++----- .../src/layers/point-cloud-layer.tsx | 7 +++- .../src/point-cloud-layer.test.ts | 4 ++ 6 files changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/capture-protocol/README.md b/packages/capture-protocol/README.md index 95729214aa..a569059558 100644 --- a/packages/capture-protocol/README.md +++ b/packages/capture-protocol/README.md @@ -24,3 +24,7 @@ const descriptor = await source.describe() For live producers, use `PushCaptureSource` directly or implement `CaptureSource.subscribe()` with the same descriptor and packet event contract. + +The package exports its TypeScript source under the `react-native` condition so Metro can consume +the workspace package from a clean checkout. Web and Node consumers continue to use the compiled +ES module output. diff --git a/packages/capture-protocol/package.json b/packages/capture-protocol/package.json index 32efc7790a..2c3184b39f 100644 --- a/packages/capture-protocol/package.json +++ b/packages/capture-protocol/package.json @@ -4,16 +4,18 @@ "description": "Transport-neutral capture-session manifests and live stream sources for Pascal", "type": "module", "main": "./dist/index.js", - "types": "./dist/index.d.ts", + "types": "./src/index.ts", "exports": { ".": { - "types": "./dist/index.d.ts", + "types": "./src/index.ts", + "react-native": "./src/index.ts", "import": "./dist/index.js", "default": "./dist/index.js" } }, "files": [ "dist", + "src", "README.md" ], "scripts": { diff --git a/packages/capture-viewer/README.md b/packages/capture-viewer/README.md index d2ab14001a..8f63c4e7c6 100644 --- a/packages/capture-viewer/README.md +++ b/packages/capture-viewer/README.md @@ -13,6 +13,7 @@ and reference renderers for RoomPlan models, device trajectories, and PLY/live p resolveSource={(locator) => createHttpCaptureSource(locator, { credentials: 'include' }) } + retryKey={retryVersion} /> ``` @@ -22,5 +23,5 @@ stream role or kind. A live transport implements `CaptureSource.subscribe()`; no WebSocket, WebRTC, or collaboration backend is required by this package. `CaptureRuntime` keeps telemetry host-neutral: pass `onError` to report source or per-stream -failures in the host. `useCaptureSource()` exposes `retry()` so host controls can recover from a -transient manifest or transport failure without remounting the viewer. +failures in the host, then increment `retryKey` to reload every affected session. Direct +`useCaptureSource()` consumers can call its `retry()` function instead. diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index ba90fc5b3f..3724e16ba1 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -16,7 +16,15 @@ import { import { type ScanNode, sceneRegistry, useScene } from '@pascal-app/core' import { ErrorBoundary, useNodeEvents } from '@pascal-app/viewer' import { createPortal, useFrame } from '@react-three/fiber' -import { type ComponentType, type ReactNode, Suspense, useEffect, useMemo, useState } from 'react' +import { + type ComponentType, + type ReactNode, + Suspense, + useEffect, + useMemo, + useRef, + useState, +} from 'react' import type { Object3D } from 'three' import { resolveCaptureFrameMatrix } from './frame' import { CaptureDeviceMotionLayer } from './layers/device-motion-layer' @@ -64,6 +72,7 @@ export type CaptureRuntimeProps = { onError?: (error: Error, context: CaptureRuntimeErrorContext) => void renderers?: Readonly> resolveSource: CaptureSourceResolver + retryKey?: number | string } const EMPTY_RENDERERS: Readonly> = {} @@ -74,6 +83,7 @@ export function CaptureRuntime({ onError, renderers = EMPTY_RENDERERS, resolveSource, + retryKey = 0, }: CaptureRuntimeProps) { const nodes = useScene((state) => state.nodes) const scans = useMemo( @@ -88,7 +98,7 @@ export function CaptureRuntime({ <> {scans.map((scan) => ( (null) + const onErrorRef = useRef(onError) const handlers = useNodeEvents(scan, 'scan') const sourceState = useCaptureSource(scan.captureSession, resolveSource, { maxPacketsPerStream, }) + useEffect(() => { + onErrorRef.current = onError + }, [onError]) + useEffect(() => { if (!sourceState.error) return - onError?.(sourceState.error, { + onErrorRef.current?.(sourceState.error, { phase: 'source', scanId: scan.id, sessionId: scan.captureSession.sessionId, }) - }, [onError, scan.captureSession.sessionId, scan.id, sourceState.error]) + }, [scan.captureSession.sessionId, scan.id, sourceState.error]) useFrame(() => { const nextTarget = sceneRegistry.nodes.get(scan.id) ?? null @@ -145,12 +160,20 @@ function CaptureSessionPortal({ if ((scan.layers[layerKey] ?? true) === false) return null if (!isCaptureStreamRenderable(stream, customRendererKeys)) return null const renderKey = captureStreamRenderKey(stream) + const packets = sourceState.packets[stream.id] ?? [] + const streamEpoch = + sourceState.streamEpochs[stream.id] ?? + `descriptor:${descriptor.revisionId ?? ''}:${stream.id}:${stream.frameId ?? ''}` + const latestPacket = packets.at(-1) + const packetRevision = latestPacket + ? `${latestPacket.generation}:${latestPacket.sequence}:${latestPacket.frameId ?? ''}` + : 'static' return ( } key={renderKey} onError={(error) => - onError?.(error, { + onErrorRef.current?.(error, { layerKey, phase: 'stream', scanId: scan.id, @@ -159,21 +182,18 @@ function CaptureSessionPortal({ streamKind: stream.kind, }) } - resetKey={`${renderKey}:${sourceState.descriptorVersion}`} + resetKey={`${renderKey}:${sourceState.descriptorVersion}:${streamEpoch}:${packetRevision}`} scope={`capture:${layerKey}`} > diff --git a/packages/capture-viewer/src/layers/point-cloud-layer.tsx b/packages/capture-viewer/src/layers/point-cloud-layer.tsx index 49d99e2f01..34274604c4 100644 --- a/packages/capture-viewer/src/layers/point-cloud-layer.tsx +++ b/packages/capture-viewer/src/layers/point-cloud-layer.tsx @@ -141,8 +141,11 @@ function parsePointPayload( } function numericArray(value: unknown): number[] | null { - if (Array.isArray(value) && value.every((entry) => typeof entry === 'number')) return value - if (ArrayBuffer.isView(value)) return Array.from(value as unknown as ArrayLike) + if (Array.isArray(value) && value.every((entry) => Number.isFinite(entry))) return value + if (ArrayBuffer.isView(value)) { + const entries = Array.from(value as unknown as ArrayLike) + return entries.every(Number.isFinite) ? entries : null + } return null } diff --git a/packages/capture-viewer/src/point-cloud-layer.test.ts b/packages/capture-viewer/src/point-cloud-layer.test.ts index 0d2a41cdd1..bb47013797 100644 --- a/packages/capture-viewer/src/point-cloud-layer.test.ts +++ b/packages/capture-viewer/src/point-cloud-layer.test.ts @@ -37,4 +37,8 @@ describe('buildPointCloudData', () => { expect([...data.positions]).toEqual([1, 0, 0, 2, 0, 0]) expect(data.colors).toBeNull() }) + + test('drops non-finite live packet geometry', () => { + expect(buildPointCloudData([packet(2, [0, 0, Number.NaN])], 100).positions).toHaveLength(0) + }) }) From e75611d5b6747ae6f1e26a378937c9d4080edb32 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Fri, 21 Aug 2026 18:23:34 -0400 Subject: [PATCH 10/12] feat(capture): support host layer visibility defaults --- packages/capture-viewer/README.md | 4 ++++ .../capture-viewer/src/capture-runtime.tsx | 9 ++++++++- packages/capture-viewer/src/index.ts | 1 + .../src/layer-visibility.test.ts | 19 +++++++++++++++++++ .../capture-viewer/src/layer-visibility.ts | 9 +++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 packages/capture-viewer/src/layer-visibility.test.ts create mode 100644 packages/capture-viewer/src/layer-visibility.ts diff --git a/packages/capture-viewer/README.md b/packages/capture-viewer/README.md index 8f63c4e7c6..0821891695 100644 --- a/packages/capture-viewer/README.md +++ b/packages/capture-viewer/README.md @@ -25,3 +25,7 @@ WebSocket, WebRTC, or collaboration backend is required by this package. `CaptureRuntime` keeps telemetry host-neutral: pass `onError` to report source or per-stream failures in the host, then increment `retryKey` to reload every affected session. Direct `useCaptureSource()` consumers can call its `retry()` function instead. + +Hosts can pass `defaultLayerVisibility` to keep expensive optional layers disabled until a user +enables them. Persisted values in the scan node's `layers` map always override those host defaults; +without host defaults, every available layer remains visible for backwards compatibility. diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index 3724e16ba1..d6db59f9e7 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -27,6 +27,7 @@ import { } from 'react' import type { Object3D } from 'three' import { resolveCaptureFrameMatrix } from './frame' +import { isCaptureLayerVisible } from './layer-visibility' import { CaptureDeviceMotionLayer } from './layers/device-motion-layer' import { CapturePointCloudLayer } from './layers/point-cloud-layer' import { CaptureRoomModel } from './layers/room-model-layer' @@ -68,6 +69,7 @@ export type CaptureRuntimeErrorContext = } export type CaptureRuntimeProps = { + defaultLayerVisibility?: Readonly> maxPacketsPerStream?: number onError?: (error: Error, context: CaptureRuntimeErrorContext) => void renderers?: Readonly> @@ -76,9 +78,11 @@ export type CaptureRuntimeProps = { } const EMPTY_RENDERERS: Readonly> = {} +const EMPTY_LAYER_VISIBILITY: Readonly> = {} type CaptureSessionScan = ScanNode & { captureSession: CaptureSessionLocator } export function CaptureRuntime({ + defaultLayerVisibility = EMPTY_LAYER_VISIBILITY, maxPacketsPerStream = 32, onError, renderers = EMPTY_RENDERERS, @@ -98,6 +102,7 @@ export function CaptureRuntime({ <> {scans.map((scan) => ( > maxPacketsPerStream: number onError?: (error: Error, context: CaptureRuntimeErrorContext) => void renderers: Readonly> @@ -157,7 +164,7 @@ function CaptureSessionPortal({ {descriptor.streams.map((stream) => { const layerKey = captureLayerKey(stream) - if ((scan.layers[layerKey] ?? true) === false) return null + if (!isCaptureLayerVisible(scan.layers, layerKey, defaultLayerVisibility)) return null if (!isCaptureStreamRenderable(stream, customRendererKeys)) return null const renderKey = captureStreamRenderKey(stream) const packets = sourceState.packets[stream.id] ?? [] diff --git a/packages/capture-viewer/src/index.ts b/packages/capture-viewer/src/index.ts index 65ffe492b6..a386ff3df6 100644 --- a/packages/capture-viewer/src/index.ts +++ b/packages/capture-viewer/src/index.ts @@ -8,6 +8,7 @@ export { type CaptureStreamRendererProps, } from './capture-runtime' export { resolveCaptureFrameMatrix } from './frame' +export { isCaptureLayerVisible } from './layer-visibility' export { CaptureDeviceMotionLayer, DEVICE_MOTION_PLAYBACK_SPEED, diff --git a/packages/capture-viewer/src/layer-visibility.test.ts b/packages/capture-viewer/src/layer-visibility.test.ts new file mode 100644 index 0000000000..68b55cd9c9 --- /dev/null +++ b/packages/capture-viewer/src/layer-visibility.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'bun:test' +import { isCaptureLayerVisible } from './layer-visibility' + +describe('isCaptureLayerVisible', () => { + test('keeps capture layers visible when the host has no default', () => { + expect(isCaptureLayerVisible({}, 'pointCloud')).toBe(true) + }) + + test('uses the host default for an unset layer', () => { + expect(isCaptureLayerVisible({}, 'pointCloud', { pointCloud: false })).toBe(false) + }) + + test('lets persisted scene visibility override the host default', () => { + expect(isCaptureLayerVisible({ pointCloud: true }, 'pointCloud', { pointCloud: false })).toBe( + true, + ) + expect(isCaptureLayerVisible({ model: false }, 'model', { model: true })).toBe(false) + }) +}) diff --git a/packages/capture-viewer/src/layer-visibility.ts b/packages/capture-viewer/src/layer-visibility.ts new file mode 100644 index 0000000000..8268e0cf6e --- /dev/null +++ b/packages/capture-viewer/src/layer-visibility.ts @@ -0,0 +1,9 @@ +const EMPTY_LAYER_VISIBILITY: Readonly> = {} + +export function isCaptureLayerVisible( + layers: Readonly>, + layerKey: string, + defaultLayerVisibility: Readonly> = EMPTY_LAYER_VISIBILITY, +): boolean { + return layers[layerKey] ?? defaultLayerVisibility[layerKey] ?? true +} From c76d474aa43af60d1944949d0565c0a3a388acb4 Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Fri, 21 Aug 2026 19:40:22 -0400 Subject: [PATCH 11/12] fix(capture): unmount hidden scene layers --- packages/capture-viewer/README.md | 2 ++ .../capture-viewer/src/capture-runtime.tsx | 28 +++++++++++++------ packages/capture-viewer/src/index.ts | 7 ++++- .../src/layer-visibility.test.ts | 28 ++++++++++++++++++- .../capture-viewer/src/layer-visibility.ts | 15 ++++++++++ .../capture-viewer/src/source-state.test.ts | 25 +++++++++++++++++ packages/capture-viewer/src/source-state.ts | 20 +++++++++++-- packages/nodes/src/scan/renderer.tsx | 5 ++-- .../viewer/src/systems/scan/scan-system.tsx | 10 +++---- 9 files changed, 120 insertions(+), 20 deletions(-) diff --git a/packages/capture-viewer/README.md b/packages/capture-viewer/README.md index 0821891695..01c04f61d5 100644 --- a/packages/capture-viewer/README.md +++ b/packages/capture-viewer/README.md @@ -29,3 +29,5 @@ failures in the host, then increment `retryKey` to reload every affected session Hosts can pass `defaultLayerVisibility` to keep expensive optional layers disabled until a user enables them. Persisted values in the scan node's `layers` map always override those host defaults; without host defaults, every available layer remains visible for backwards compatibility. +Hidden sessions and layers are unmounted rather than only made visually transparent, so they stop +raycasting, artifact work, animation, and live packet subscriptions while disabled. diff --git a/packages/capture-viewer/src/capture-runtime.tsx b/packages/capture-viewer/src/capture-runtime.tsx index d6db59f9e7..93455ebb47 100644 --- a/packages/capture-viewer/src/capture-runtime.tsx +++ b/packages/capture-viewer/src/capture-runtime.tsx @@ -14,12 +14,13 @@ import { DeviceMotionTrajectorySchema, } from '@pascal-app/capture-protocol' import { type ScanNode, sceneRegistry, useScene } from '@pascal-app/core' -import { ErrorBoundary, useNodeEvents } from '@pascal-app/viewer' +import { ErrorBoundary, useNodeEvents, useViewer } from '@pascal-app/viewer' import { createPortal, useFrame } from '@react-three/fiber' import { type ComponentType, type ReactNode, Suspense, + useCallback, useEffect, useMemo, useRef, @@ -27,7 +28,7 @@ import { } from 'react' import type { Object3D } from 'three' import { resolveCaptureFrameMatrix } from './frame' -import { isCaptureLayerVisible } from './layer-visibility' +import { isCaptureSessionVisible, isCaptureStreamVisible } from './layer-visibility' import { CaptureDeviceMotionLayer } from './layers/device-motion-layer' import { CapturePointCloudLayer } from './layers/point-cloud-layer' import { CaptureRoomModel } from './layers/room-model-layer' @@ -90,12 +91,16 @@ export function CaptureRuntime({ retryKey = 0, }: CaptureRuntimeProps) { const nodes = useScene((state) => state.nodes) + const showScans = useViewer((state) => state.showScans) const scans = useMemo( () => Object.values(nodes).filter( - (node): node is CaptureSessionScan => node.type === 'scan' && node.captureSession !== null, + (node): node is CaptureSessionScan => + node.type === 'scan' && + node.captureSession !== null && + isCaptureSessionVisible(showScans, node.visible), ), - [nodes], + [nodes, showScans], ) return ( @@ -133,8 +138,16 @@ function CaptureSessionPortal({ const [target, setTarget] = useState(null) const onErrorRef = useRef(onError) const handlers = useNodeEvents(scan, 'scan') + const customRendererKeys = useMemo(() => new Set(Object.keys(renderers)), [renderers]) + const streamFilter = useCallback( + (stream: CaptureStreamDescriptor) => + isCaptureStreamVisible(stream, scan.layers, defaultLayerVisibility) && + isCaptureStreamRenderable(stream, customRendererKeys), + [customRendererKeys, defaultLayerVisibility, scan.layers], + ) const sourceState = useCaptureSource(scan.captureSession, resolveSource, { maxPacketsPerStream, + streamFilter, }) useEffect(() => { @@ -157,15 +170,14 @@ function CaptureSessionPortal({ const descriptor = sourceState.descriptor const source = sourceState.source - const customRendererKeys = useMemo(() => new Set(Object.keys(renderers)), [renderers]) if (!(target && descriptor && source)) return null + const visibleStreams = descriptor.streams.filter(streamFilter) + return createPortal( - {descriptor.streams.map((stream) => { + {visibleStreams.map((stream) => { const layerKey = captureLayerKey(stream) - if (!isCaptureLayerVisible(scan.layers, layerKey, defaultLayerVisibility)) return null - if (!isCaptureStreamRenderable(stream, customRendererKeys)) return null const renderKey = captureStreamRenderKey(stream) const packets = sourceState.packets[stream.id] ?? [] const streamEpoch = diff --git a/packages/capture-viewer/src/index.ts b/packages/capture-viewer/src/index.ts index a386ff3df6..93b16c1719 100644 --- a/packages/capture-viewer/src/index.ts +++ b/packages/capture-viewer/src/index.ts @@ -8,7 +8,11 @@ export { type CaptureStreamRendererProps, } from './capture-runtime' export { resolveCaptureFrameMatrix } from './frame' -export { isCaptureLayerVisible } from './layer-visibility' +export { + isCaptureLayerVisible, + isCaptureSessionVisible, + isCaptureStreamVisible, +} from './layer-visibility' export { CaptureDeviceMotionLayer, DEVICE_MOTION_PLAYBACK_SPEED, @@ -27,6 +31,7 @@ export { export { appendCapturePacket, type CaptureSourceState, + captureSubscriptionStreamIds, type UseCaptureSourceOptions, useCaptureSource, } from './source-state' diff --git a/packages/capture-viewer/src/layer-visibility.test.ts b/packages/capture-viewer/src/layer-visibility.test.ts index 68b55cd9c9..d447afe057 100644 --- a/packages/capture-viewer/src/layer-visibility.test.ts +++ b/packages/capture-viewer/src/layer-visibility.test.ts @@ -1,5 +1,9 @@ import { describe, expect, test } from 'bun:test' -import { isCaptureLayerVisible } from './layer-visibility' +import { + isCaptureLayerVisible, + isCaptureSessionVisible, + isCaptureStreamVisible, +} from './layer-visibility' describe('isCaptureLayerVisible', () => { test('keeps capture layers visible when the host has no default', () => { @@ -17,3 +21,25 @@ describe('isCaptureLayerVisible', () => { expect(isCaptureLayerVisible({ model: false }, 'model', { model: true })).toBe(false) }) }) + +describe('isCaptureStreamVisible', () => { + test('resolves a stream through its capture layer', () => { + const stream = { + id: 'points', + kind: 'point-cloud', + role: 'pointCloud', + availability: 'ready', + } as const + + expect(isCaptureStreamVisible(stream, {}, { pointCloud: false })).toBe(false) + expect(isCaptureStreamVisible(stream, { pointCloud: true }, { pointCloud: false })).toBe(true) + }) +}) + +describe('isCaptureSessionVisible', () => { + test('requires both the global scan display and node visibility', () => { + expect(isCaptureSessionVisible(true, true)).toBe(true) + expect(isCaptureSessionVisible(false, true)).toBe(false) + expect(isCaptureSessionVisible(true, false)).toBe(false) + }) +}) diff --git a/packages/capture-viewer/src/layer-visibility.ts b/packages/capture-viewer/src/layer-visibility.ts index 8268e0cf6e..5524e7fd86 100644 --- a/packages/capture-viewer/src/layer-visibility.ts +++ b/packages/capture-viewer/src/layer-visibility.ts @@ -1,3 +1,6 @@ +import type { CaptureStreamDescriptor } from '@pascal-app/capture-protocol' +import { captureLayerKey } from '@pascal-app/capture-protocol' + const EMPTY_LAYER_VISIBILITY: Readonly> = {} export function isCaptureLayerVisible( @@ -7,3 +10,15 @@ export function isCaptureLayerVisible( ): boolean { return layers[layerKey] ?? defaultLayerVisibility[layerKey] ?? true } + +export function isCaptureStreamVisible( + stream: CaptureStreamDescriptor, + layers: Readonly>, + defaultLayerVisibility: Readonly> = EMPTY_LAYER_VISIBILITY, +): boolean { + return isCaptureLayerVisible(layers, captureLayerKey(stream), defaultLayerVisibility) +} + +export function isCaptureSessionVisible(showScans: boolean, scanVisible: boolean): boolean { + return showScans && scanVisible +} diff --git a/packages/capture-viewer/src/source-state.test.ts b/packages/capture-viewer/src/source-state.test.ts index 9aa73be7ee..f2ba53acf1 100644 --- a/packages/capture-viewer/src/source-state.test.ts +++ b/packages/capture-viewer/src/source-state.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test' import type { CaptureStreamPacket } from '@pascal-app/capture-protocol' import { appendCapturePacket, + captureSubscriptionStreamIds, nextCaptureStreamEpoch, retainLiveCapturePackets, } from './source-state' @@ -108,3 +109,27 @@ describe('retainLiveCapturePackets', () => { ).toEqual({}) }) }) + +describe('captureSubscriptionStreamIds', () => { + const descriptor = { + schemaVersion: 2, + sessionId: 'capture_123', + state: 'live', + clocks: [], + coordinateFrames: [], + streams: [ + { id: 'model', kind: 'room-model', role: 'model', availability: 'ready' }, + { id: 'points', kind: 'point-cloud', role: 'pointCloud', availability: 'live' }, + ], + } as const + + test('leaves subscriptions unrestricted without a filter', () => { + expect(captureSubscriptionStreamIds(descriptor, undefined)).toBeUndefined() + }) + + test('subscribes only to streams accepted by the host', () => { + expect( + captureSubscriptionStreamIds(descriptor, (stream) => stream.role !== 'pointCloud'), + ).toEqual(['model']) + }) +}) diff --git a/packages/capture-viewer/src/source-state.ts b/packages/capture-viewer/src/source-state.ts index 7bcf32e7b4..434040771e 100644 --- a/packages/capture-viewer/src/source-state.ts +++ b/packages/capture-viewer/src/source-state.ts @@ -3,6 +3,7 @@ import type { CaptureSessionLocator, CaptureSource, CaptureSourceResolver, + CaptureStreamDescriptor, CaptureStreamPacket, } from '@pascal-app/capture-protocol' import { useCallback, useEffect, useState } from 'react' @@ -22,6 +23,7 @@ type CaptureSourceSnapshot = Omit export type UseCaptureSourceOptions = { maxPacketsPerStream?: number + streamFilter?: (stream: CaptureStreamDescriptor) => boolean subscribe?: boolean } @@ -33,7 +35,7 @@ export function useCaptureSource( resolveSource: CaptureSourceResolver, options: UseCaptureSourceOptions = {}, ): CaptureSourceState { - const { maxPacketsPerStream = 32, subscribe = true } = options + const { maxPacketsPerStream = 32, streamFilter, subscribe = true } = options const [retryVersion, setRetryVersion] = useState(0) const [state, setState] = useState({ descriptor: null, @@ -75,11 +77,12 @@ export function useCaptureSource( abort.signal, retryVersion, maxPacketsPerStream, + streamFilter, subscribe, setState, ) return () => abort.abort() - }, [locator, maxPacketsPerStream, resolveSource, retryVersion, subscribe]) + }, [locator, maxPacketsPerStream, resolveSource, retryVersion, streamFilter, subscribe]) const retry = useCallback(() => setRetryVersion((current) => current + 1), []) return { ...state, retry } @@ -91,6 +94,7 @@ async function consumeCaptureSource( signal: AbortSignal, descriptorVersion: number, maxPacketsPerStream: number, + streamFilter: ((stream: CaptureStreamDescriptor) => boolean) | undefined, subscribe: boolean, setState: ( update: CaptureSourceSnapshot | ((current: CaptureSourceSnapshot) => CaptureSourceSnapshot), @@ -111,7 +115,8 @@ async function consumeCaptureSource( }) if (!(subscribe && source.subscribe)) return - const iterator = source.subscribe({ signal })[Symbol.asyncIterator]() + const streamIds = captureSubscriptionStreamIds(descriptor, streamFilter) + const iterator = source.subscribe({ signal, streamIds })[Symbol.asyncIterator]() const closeIterator = () => void iterator.return?.() signal.addEventListener('abort', closeIterator, { once: true }) try { @@ -175,6 +180,15 @@ async function consumeCaptureSource( } } +export function captureSubscriptionStreamIds( + descriptor: CaptureSessionDescriptor, + streamFilter: ((stream: CaptureStreamDescriptor) => boolean) | undefined, +): readonly string[] | undefined { + return streamFilter + ? descriptor.streams.filter(streamFilter).map((stream) => stream.id) + : undefined +} + export function retainLiveCapturePackets( packetsByStream: Readonly>, descriptor: CaptureSessionDescriptor, diff --git a/packages/nodes/src/scan/renderer.tsx b/packages/nodes/src/scan/renderer.tsx index db9398076e..98376a65db 100644 --- a/packages/nodes/src/scan/renderer.tsx +++ b/packages/nodes/src/scan/renderer.tsx @@ -7,6 +7,7 @@ import type { Group, Material, Mesh } from 'three' export const ScanRenderer = ({ node }: { node: ScanNode }) => { const showScans = useViewer((s) => s.showScans) + const visible = showScans && node.visible const ref = useRef(null!) useRegistry(node.id, 'scan', ref) @@ -16,9 +17,9 @@ export const ScanRenderer = ({ node }: { node: ScanNode }) => { ref={ref} rotation={node.rotation} scale={[node.scale, node.scale, node.scale]} - visible={showScans && node.visible} + visible={visible} > - {(node.layers?.model ?? true) && node.url && ( + {visible && (node.layers?.model ?? true) && node.url && ( )} diff --git a/packages/viewer/src/systems/scan/scan-system.tsx b/packages/viewer/src/systems/scan/scan-system.tsx index 5704c690ad..9b50959f5c 100644 --- a/packages/viewer/src/systems/scan/scan-system.tsx +++ b/packages/viewer/src/systems/scan/scan-system.tsx @@ -1,19 +1,19 @@ -import { sceneRegistry } from '@pascal-app/core' +import { type ScanNode, sceneRegistry, useScene } from '@pascal-app/core' import { useEffect } from 'react' import useViewer from '../../store/use-viewer' export const ScanSystem = () => { const showScans = useViewer((state) => state.showScans) + const nodes = useScene((state) => state.nodes) useEffect(() => { const scans = sceneRegistry.byType.scan || new Set() scans.forEach((scanId) => { const node = sceneRegistry.nodes.get(scanId) - if (node) { - node.visible = showScans - } + const scan = nodes[scanId as ScanNode['id']] + if (node && scan?.type === 'scan') node.visible = showScans && scan.visible }) - }, [showScans]) + }, [nodes, showScans]) return null } From 8dda82063e85c5d212582529dad1543ffded61dd Mon Sep 17 00:00:00 2001 From: Aymeric Rabot Date: Sun, 23 Aug 2026 23:53:58 -0400 Subject: [PATCH 12/12] chore: align capture lockfile with main --- bun.lock | 722 +++++++++++++++++++++++++------------------------------ 1 file changed, 327 insertions(+), 395 deletions(-) diff --git a/bun.lock b/bun.lock index 6dde1db07d..fa38b54b99 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,6 @@ { "lockfileVersion": 1, - "configVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "editor", @@ -385,21 +385,13 @@ "packages": { "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - "@apm-js-collab/code-transformer": ["@apm-js-collab/code-transformer@0.18.1", "", { "dependencies": { "@types/estree": "^1.0.8", "astring": "^1.9.0", "esquery": "^1.7.0", "meriyah": "^6.1.4", "semifies": "^1.0.0", "source-map": "^0.6.0" }, "bin": { "code-transformer": "cli.js" } }, "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ=="], - - "@apm-js-collab/code-transformer-bundler-plugins": ["@apm-js-collab/code-transformer-bundler-plugins@0.7.4", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.1", "es-module-lexer": "^2.1.0", "magic-string": "^0.30.21", "module-details-from-path": "^1.0.4" } }, "sha512-nAfOeZPSUAQvJa1iFT/5oCrTm5YQhMMrfCNthNnaXHZiOQhu1KGuLoIx7HtbAi3wfwaBYLaICPIeenIaEwcXIg=="], - - "@apm-js-collab/tracing-hooks": ["@apm-js-collab/tracing-hooks@0.13.0", "", { "dependencies": { "@apm-js-collab/code-transformer": "^0.18.0", "debug": "^4.4.1", "module-details-from-path": "^1.0.4" } }, "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw=="], - - "@astrojs/compiler": ["@astrojs/compiler@4.0.0", "", {}, "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA=="], - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@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" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], - "@babel/generator": ["@babel/generator@7.29.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="], + "@babel/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], @@ -417,37 +409,37 @@ "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], - "@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="], + "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], - "@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="], + "@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="], - "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], + "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - "@biomejs/biome": ["@biomejs/biome@2.5.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.10", "@biomejs/cli-darwin-x64": "2.5.10", "@biomejs/cli-linux-arm64": "2.5.10", "@biomejs/cli-linux-arm64-musl": "2.5.10", "@biomejs/cli-linux-x64": "2.5.10", "@biomejs/cli-linux-x64-musl": "2.5.10", "@biomejs/cli-win32-arm64": "2.5.10", "@biomejs/cli-win32-x64": "2.5.10" }, "bin": { "biome": "bin/biome" } }, "sha512-WRKXARA3kTuiV5sxqTpobJ/I0MVd4vk3pOL6wnp5az4LntFIhWTj1RWZq3DI9PCEN3lXcqy7p5aqUHzvq8AXyQ=="], + "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.5.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ItCrxKK6SXVT6flYs0qIuBd4AA3TTTl4d66Re6YI2FuGZnN85NmuYNzkiTJUyYw8qBLv69L5zTUB6uyWd++h3Q=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.5.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-yLsPU9pAmtChXDu8vhKAzErqe+LeeYuwuUB2FZMkRitsmdodxsYRa9KHrFispsUHzzOu+9HB3nP/TQxyia+Sjw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-VG8uQW/86a1roLaIFvtIbEigxIdzdJ190oGyg1tV7VYeQtOS+x10sflk7WbuXgw91EtZX5DlIIIej1YqkNLlcg=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-t1QAKZwQJRB4dvgJSgFiQ4BNfNPChg69BNonz854qLVxnjT3UvDzQg9mbkTJRu35ZqU0Rw10A73J8Urgbg2RPw=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-4O6T0eq2heoHZN0a9UX+rWQoxXEBaKf+lRi2hbsGlHneUz9BWXM76nEWMK7Eeq8gzMxR1khQB6BFpAASpeXqGg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-pgDDqp9JybHm2I0KRgzN6i4+lt8xu4iqxUwLzglUMmOmyRTU1AYBGKzh9sNMOtIjah7xoWvKHlLVetvyifzoiQ=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.5.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-pxAbxduPO4xq/Cvgaa2lOrs9BB0hEXmmDqfMNP4ZOffGOkUrD1/QGw9UAMpFQpX2P8MqTIIRuQKcmetum4Oa6A=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.10", "", { "os": "win32", "cpu": "x64" }, "sha512-M+2dgBsl3lXRiTfgPVc2p3anS4Tocojke4rzFLScZ2Y/wmF+36dRb1iHCLiyGqOzQGyTplZH1HnEYviiAqi3nA=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="], - "@clack/core": ["@clack/core@1.4.3", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ=="], + "@clack/core": ["@clack/core@1.4.1", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw=="], - "@clack/prompts": ["@clack/prompts@1.7.0", "", { "dependencies": { "@clack/core": "1.4.3", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A=="], + "@clack/prompts": ["@clack/prompts@1.5.1", "", { "dependencies": { "@clack/core": "1.4.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-zccHj2z2oCCO4yrDiRSlFOxWerGqRiysP7a5jPK6uoI9URKAquwY42Dd/iUP8JWHxEzdRe4TlbvZCo8z1/mhrw=="], "@dgreenheck/ez-tree": ["@dgreenheck/ez-tree@1.1.0", "", { "peerDependencies": { "three": ">=0.167" } }, "sha512-6pvS6hD6B6h00dm0SnkgYeT4ABU5Y1Z9M44p1tXiV5C0eKrQy2sKECXshoaUv0qAOqYVL68w/PwadUxDFDiHUg=="], @@ -461,11 +453,13 @@ "@dnd-kit/utilities": ["@dnd-kit/utilities@3.2.2", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg=="], - "@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="], + "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.70", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.70" } }, "sha512-3VXuL63IDmq13We+ApRKn2JW3Rb9g5gj1YEmfb8u2b73norur1VsIJ/pRE4qjShevg19dQYi2JsLawSZ6gApug=="], + + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], @@ -477,21 +471,21 @@ "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.6", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.3.0", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA=="], + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], - "@eslint/js": ["@eslint/js@9.39.5", "", {}, "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A=="], + "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], - "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="], + "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], - "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="], + "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], - "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.9", "", { "dependencies": { "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg=="], + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="], - "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="], + "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], "@gltf-transform/core": ["@gltf-transform/core@4.4.2", "", { "dependencies": { "property-graph": "^4.1.0" } }, "sha512-qsWKwNSwK+2s834Mt4xbYcyHqCrgNFP7hIv5s487JxebngRfDgelpghNF+kSswGb2/NuapasfK3UViFoSJJoMg=="], @@ -499,7 +493,7 @@ "@gltf-transform/functions": ["@gltf-transform/functions@4.4.2", "", { "dependencies": { "@gltf-transform/core": "^4.4.2", "@gltf-transform/extensions": "^4.4.2", "ktx-parse": "^1.1.0", "ndarray": "^1.0.19", "ndarray-lanczos": "^0.3.0", "ndarray-pixels": "^5.0.1" } }, "sha512-dclXgv9TshMaWBqPDUYd4xTwBQ2PpuR8p0Y9pokrRzGQDUPXRP6lTDzbqT0UmEmxFSvRyPJjvOWUmzeiRafpvw=="], - "@hono/node-server": ["@hono/node-server@2.1.1", "", { "peerDependencies": { "hono": "^4" } }, "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg=="], + "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], @@ -587,11 +581,23 @@ "@mint/pascal-plugin": ["@mint/pascal-plugin@github:mintdotgg/mint-pascal-plugin#902c546", { "peerDependencies": { "@pascal-app/core": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/editor": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "@pascal-app/viewer": ">=0.9.2 <1.0.0 || >=1.0.0-beta.1 <1.0.0", "react": "^18 || ^19", "three": "^0.185" } }, "mintdotgg-mint-pascal-plugin-902c546", "sha512-/itUH9r9OIP8ZPrklW8iWe6B2SDOtlL1m8r9hlVM4Rw5josYtDdkDKQ37FbanvxxuUKcQnukHbtxWe3svRaCrQ=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.30.0", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], "@monogrid/gainmap-js": ["@monogrid/gainmap-js@3.4.0", "", { "dependencies": { "promise-worker-transferable": "^1.0.4" }, "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="], + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="], + + "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="], + + "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="], + + "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], "@next/env": ["@next/env@16.3.0", "", {}, "sha512-o9r1S0BNiNreHP9Vs+Qnqd9kviDkJh8xIACY7UFZSmiGbbQRzPBBosvHzAU4TULHOIuOj/18RSsyz2qrREmIFw=="], @@ -625,139 +631,139 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@number-flow/react": ["@number-flow/react@0.6.2", "", { "dependencies": { "esm-env": "^1.1.4", "number-flow": "0.6.2" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-WjZuV4aA+vhRCgCF+adGLgFVVAJ8vdvq6EchRT2FiBIgElTXtDOA3YgkcMr9UHpvpS9v4H70AB5wZv0D9jc3QA=="], + "@number-flow/react": ["@number-flow/react@0.6.0", "", { "dependencies": { "esm-env": "^1.1.4", "number-flow": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-77Yfc9+zkV2UDSP8phhZzxJGuwxi/Tt1TikmipL+1r3e9GFKEYDZ1XwInj67NoSt3OnOB0KLvvcl3lfPZgBHVQ=="], "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="], - "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w=="], + "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA=="], - "@opentelemetry/core": ["@opentelemetry/core@2.10.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ=="], + "@opentelemetry/core": ["@opentelemetry/core@2.7.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw=="], - "@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw=="], + "@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w=="], - "@opentelemetry/resources": ["@opentelemetry/resources@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA=="], + "@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], - "@opentelemetry/sdk-trace": ["@opentelemetry/sdk-trace@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ=="], + "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw=="], - "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.10.0", "", { "dependencies": { "@opentelemetry/core": "2.10.0", "@opentelemetry/resources": "2.10.0", "@opentelemetry/sdk-trace": "2.10.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ=="], + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.41.1", "", {}, "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA=="], - "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], + "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.132.0", "", { "os": "android", "cpu": "arm" }, "sha512-KrLaPWa5c9Y7LkW+rKkaUE3y7DBDrQtaf7rlsSDfv6KAHUjgzAIRA761Lrrp6//Yd/Rlie/yEOt9YENCoJnOcw=="], - "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.143.0", "", { "os": "android", "cpu": "arm" }, "sha512-n9uozULWflPqBtdmI8lAabLqGKNgLVNN0ZH8HfgCwpKGNtzRzauB76jTiW/3YLkcA7N1zskpi9GdVnZuu1SAvg=="], + "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.132.0", "", { "os": "android", "cpu": "arm64" }, "sha512-SThDrSeamB/kG2+NxcJ5/wSLcV6dUqDknrPLqFYQ0ST/55mtBP4M7Q/f3QbubH6aAd11wpzZn/nwbVRSdobOpg=="], - "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.143.0", "", { "os": "android", "cpu": "arm64" }, "sha512-9BbdjHETk6O3zH/DDid9IgBtF0GlpLabNKN231uraXpRDSfY+iiZxTP5bk1Z63GBownVdhdINFIeddmMz4MzpQ=="], + "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.132.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lc0f/TYoKBghE5/2Gsv7bLXk+TJZunx2Tf61X8hG4ARXdc8UYI26dCGccFSd1AyFbK3jfaNXtMnupggDbjPXdQ=="], - "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.143.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gh+6ecoHUy4/sUcolBl/1qPXKBbYNxFY0Pk0ujgQvINTMSftJY7o4yb8gOkDJPeZeB8+a+u7xTe6umoP8N5HFA=="], + "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.132.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-RG2eJIpf7C21z9HSSXFw1bTArdpKe7Y4fwcJTwRq1yCSe1vSavaN9GA1sm9KqzemTLAGVktQ+7qBTGp0vQeUZg=="], - "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.143.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-qd1hl2d+lXgHv/VQ/M9qm8TrMC5T4RqDBwtOnl+1D0QMjwcz+8AaB4JSg8STgeag0GP6a6L74XEGAsrTSJWNzQ=="], + "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.132.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wQIPntPLtJ8NcBpvKPbEv3NqzV6k8eP8tP/jE9Rg8HTg/j7urZGFSsTCPCW5k77Qfw2DM4vRvc9p3I4yq/Shvw=="], - "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.143.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-M5XXcNa7aOqLPKTR41msfghKu2yQ4xWvCm11/gwU0JzOzHNk5sgW//rVEjJ+LO48+VDAMzXTSzurUVxIDKwozw=="], + "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.132.0", "", { "os": "linux", "cpu": "arm" }, "sha512-PixKEpeSe3yxQWqNyOCBALRYc72+Tj7ILDofUl3iXo25cVOzLA6jHUhmOINRtWIPh7dbUie3QNeabwaQpZTw6w=="], - "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.143.0", "", { "os": "linux", "cpu": "arm" }, "sha512-T/GXusuOkPNQhCQCSBbcU/N8j0rAypuDBl1IyFK+lyYT594XsVz80clPC/OtbSSpBGyJxj8uYEfctxVuxVYoww=="], + "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.132.0", "", { "os": "linux", "cpu": "arm" }, "sha512-sCR+DzGHlyHKnbA2z9zWjTUhIo8Sy0enJl4RDsBwPmkxYynPatpwOAWe8W5127SlW0boqUWHGtr1NWn5UwIhXQ=="], - "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.143.0", "", { "os": "linux", "cpu": "arm" }, "sha512-oKu4RcBlXSqo3OC62dp6YTnQaZIurNDpCX3BnAM3+bJxt7s8J2TJKMnC0UYer1qhlRaDCg6wkTaTw+2IlsZ12w=="], + "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.132.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-sQBix5P2cW+IpzTcCwYxnh9yALrKSIkKJThspBvMGcygSMnbzkSvhN7SfuX1hvBk8y1XEChsdkU3ET0V5DmzUw=="], - "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.143.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WJBbD186AZmMGaSIhlktC+rPl8L3peCTXAh88Ih9uEvK0en2mPojGyCGYiL6mHtV1RPV3JyfJW5t6n5hh0lXhA=="], + "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.132.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WozHg3Kc//8Sk756HXXgMbEAvqtG+Lzb9JOojwQzIGDtN78Az2dLttkb71akWYUF/8IgYfDSlfKh4Uot8is5Vw=="], - "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.143.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-t1AcYOwEzgceadT4v5e+vaCCb0AncCA3v5AyzfBAz/tMq11qzVccXKzNHtkWdjBsgvTKwRkaUF3QvT4kot8vcQ=="], + "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.132.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CmX/ulNBOEwWTyVRmcpYKAcAizW6+OjtLJgo7fXoL9OqQvjF4VER8tPomv44vwzfSCy1BHbsB0ZlZYzYJNj4cA=="], - "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.143.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-RsnO/NoD8376LMJq8JS8TwI0ieNaFRTuNe2GVJntQg6gwZNMENZsEbknHdVwjpOmxdGLGodcwaGSbAeRr5Bgjw=="], + "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.132.0", "", { "os": "linux", "cpu": "none" }, "sha512-j9oQS+hM90SdhviNGWbPgT4+Rlq+ac++q/zjgwPD1mVHgxHzATvoRGtDx0sXGmFOQ9J9YkwAhYGb5MAHL6TAsA=="], - "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.143.0", "", { "os": "linux", "cpu": "none" }, "sha512-48fSVfR9TZi5CASZFyv0VC6z6BCoeihFsX031mAD/oSH7d9PYsPgIqza7d9mjP7Z2KTEpTFyH6SIu0Ui6R1vdg=="], + "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.132.0", "", { "os": "linux", "cpu": "none" }, "sha512-bLz+Xi+Agnfmd7kWPEsSVwCn2k4EyIalZkNBcQ0OGIv9rqn8VgCPLNd03tM9mKX/5TdlvDXalz0q71BIrOPNqg=="], - "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.143.0", "", { "os": "linux", "cpu": "none" }, "sha512-T8CpdD+SfE01DnIOD4HpVxu0ZJOfMJ/VhCvikKfaXAxkZ+9veyLM/D2hpi7Y2hFUyPmVQO3FNZHmYzV/WlVR4g=="], + "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.132.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-U6t2qbJU0ypTfyj9QV3W1Y6mITDTL8ai/OR6NUn85vyHthOvobKWgXzU4tu0EskSzlpuVFz1g0jFGulDIUKHxQ=="], - "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.143.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-QLdeMsCcacenPEFsfxnBUDF1y6opyz5+fmOz9bfD5Y7fiGCMupUCuB3KTPQhNwshIG1P9fPqar9MHxuBDd4bwQ=="], + "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.132.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WcEaSNHFk8yz5YFlQQAlhq6jOFmZBB/RKE7uzhyCIf+pF1Lmv9gUH4221mle2Gd9iHyWT3ySNph8yZgb1xYdWg=="], - "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.143.0", "", { "os": "linux", "cpu": "x64" }, "sha512-659ujfqLy6k7cuH3sbzhd8b+ztSq+i6E2E9pG78Q0BmHjAExfGIdgc8cGgMdwAozDXeZFHkJ+LXYJdWsaGdgyw=="], + "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.132.0", "", { "os": "linux", "cpu": "x64" }, "sha512-iQrV4iJzQgRwK3BWRmQl1C3C6g3wYpXN2WLdQdyR+efoUnncdShZAVp9OgcojtlD3MDRbuOMGG3SjxF4fL4nlQ=="], - "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.143.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/Mw/9j4TfZcnKphPrzOE6t4MMknXadcAAuVUlDRTF/ETWB5xOgQvOJV2Mh9We/bWxZdoxaGAdc+hy4GuYwQ2yQ=="], + "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.132.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FWzmUGrZ6GUby4U7WIwcCtab6tdmlTO3xTRRKyb5kjIJVEiaUAT8animUG/nK8ZCA8gkRkPOTId4rl6uTqUmJQ=="], - "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.143.0", "", { "os": "none", "cpu": "arm64" }, "sha512-8rIKWR2BFuifbIK/1XB9wTaSdtuJ25dlE7ZQYDnEwj/2xH2vHsxnvIjHT3ZjSVuLLwGGlSslIG/fbOJ8TV8rTw=="], + "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.132.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-TlbMppxJI5CjWDes0QaP6G3aneVg1yikBu5QYI+DUShF9WDL66ccgKFNNGmi/Wybtszw6hxwAvv76T4DaPKnHw=="], - "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.143.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-5U9kQYMfRRI6Zq7KDxgbIP0RMnKrfn3gLepRMgJuRkPSUALTiRCk9d/uyhb4lGDjUdzwK7mBkKqhLgzBPCmLpQ=="], + "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.132.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-RH/NbFjGKqdUAUi7Oh3LQPxUk2hsWFEEQ38HSnbRQT8QjBZFKqL1fMbmsB3N4jy/KPh9iX94+9dmkEMBBbambw=="], - "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.143.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-25P7AaHk4R88Yv2XH4gToDVmh0cOu+bEURQU10CRrmvgabfRArSGAP5osmwUKeSUHj0VS50upbpbRWWW/m7mHA=="], + "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.132.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-JUr4jQY9jxoIB/YTLXr6XofSi5xikj6p5/Ns1h0VOBDT0j1jKU+kMsv2xxv51RwnETcXpA1Yw/9oUAfcqfaqEA=="], - "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.143.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ORMh3JE1s6V7ySicdRK7vgaDQnn5o+UHg9ct989PlWHbel8O9ARrmWXM6kZjrBMtNucxNayQ8g69G0VfWzhANw=="], + "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.132.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2dapgHpA5X8DSXF4AU36hJWYf6zP0tKjMXFRAZFBD62pkevW/uhFDXoFH9Y/3Fd2EtDrw5ByNnR1wVE9X9y0SQ=="], - "@oxc-project/types": ["@oxc-project/types@0.143.0", "", {}, "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA=="], + "@oxc-project/types": ["@oxc-project/types@0.132.0", "", {}, "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ=="], - "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA=="], + "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.20.0", "", { "os": "android", "cpu": "arm" }, "sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg=="], - "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg=="], + "@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.20.0", "", { "os": "android", "cpu": "arm64" }, "sha512-QqslZAuFQG8Q9xm7JuIn8JUbvywhSBMVhuQHtYW+auirZJloS41oxUUaBXk7uUhZJgp44c5zQLeVvmFaDQB+2Q=="], - "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w=="], + "@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.20.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MUcavykj2ewlR+kc5arpg4tC2RvzJkUxWtNv74pf7lcNk00GpIpN43vXMj+j6r4eMmfZhlb8hueKoIb8e9kAGQ=="], - "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q=="], + "@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.20.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-BGB16nRUK5Etiv//ihPyzj8Lj1px0mhh4YIfe0FDf045ywknfSm0GEbiRESpr6Q4K82AvnyaRIhhluHByvS4bg=="], - "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw=="], + "@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.20.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JZgtePaqj3qmD5XFHJaSLWzHRxQu0LaPkdoM1KJXYADvAaa83ijXHclV3ej3CueeW0wxfIAbGCZVP45J0CA7uQ=="], - "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg=="], + "@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.20.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hOQ/p3ry3v3SchUBXicrrnszaI/UmYzM4wtS4RGfwgVUX7a+HbyQSzJ5aOzu+o6XZkFkS3ZXN4PZAzhOb77OSg=="], - "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA=="], + "@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.20.0", "", { "os": "linux", "cpu": "arm" }, "sha512-2ArPksaw0AqeuGBfoS715VF+JvJQAhD2niWgjE5hVO+L+nAfikVQopvngCMX9x4BD8itWoQ3dnikrQyl5Ho5Jg=="], - "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA=="], + "@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.20.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg=="], - "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw=="], + "@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.20.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw=="], - "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA=="], + "@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.20.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ=="], - "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw=="], + "@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.20.0", "", { "os": "linux", "cpu": "none" }, "sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw=="], - "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w=="], + "@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.20.0", "", { "os": "linux", "cpu": "none" }, "sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg=="], - "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ=="], + "@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.20.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g=="], - "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg=="], + "@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.20.0", "", { "os": "linux", "cpu": "x64" }, "sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g=="], - "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw=="], + "@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.20.0", "", { "os": "linux", "cpu": "x64" }, "sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ=="], - "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg=="], + "@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.20.0", "", { "os": "none", "cpu": "arm64" }, "sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ=="], - "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.24.2", "", { "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q=="], + "@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.20.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-Tn0y1XOFYHNfK1wp1Z5QK8Rcld/bsOwRISQXfqAZ5IBpv8Gz1IvV39fUWNprqNdRizgcvFhOzWwFun2zkJsyBg=="], - "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg=="], + "@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.20.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-qPi25YNPe4YenS8MgsQU2+bIFHxxpLx1LVna2444cEHqNPhNjvWf9zqj4aWE43H9LpAsTmkkAlA3eL5ElBU3mA=="], - "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw=="], + "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.20.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Wb14jWEW8huH6It9F6sXd9vrYmIS7pMrgkU6sxpLxkP+9z+wRgs71hUEhRpcn8FOXAFa27FVWfY2tRpbfTzfLw=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.77.0", "", { "os": "android", "cpu": "arm" }, "sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.69.0", "", { "os": "android", "cpu": "arm" }, "sha512-DKQQbD5cZ/MYfDgDI7YGyGD9FSxABlsBsYFo5p26lloob543tP9+4N3guwdXIYJN+7HSZxLe8YJuwcOWw5qnHg=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.77.0", "", { "os": "android", "cpu": "arm64" }, "sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.69.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lEhb+I5pr4inux+JFwfCa1HRq3Os7NirEFQ0H1I35SVEHPm6byX0Ah47xmRha3qi6LAkxUcxViL8o/9PivjzBg=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.77.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.69.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GY2YE8lOZW59BW1Ia1y+1gR0XyjrZRvVWHAr8LGeGhYHE0OQJ/7cRKXTkx1P+E9/6awEc3SX8a68SFTjh/E//A=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.77.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.69.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ax1oZnOjHX3LB7myQyHEaQkDwfLb6str3/nSP6O7EVUviQGNkEGzGV0EqcBJWK+Ufwx0l4xPgyYayurvhAdl2Q=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.77.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.69.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kHWeHv4g2h8NY+mpCxzCtY4uerMJWTN/TSnNj1CPbakFpHEJ6cTya2wWV0pDSYWOJ2+0UiEbhn3AtXxHtsnKjg=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.77.0", "", { "os": "linux", "cpu": "arm" }, "sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.69.0", "", { "os": "linux", "cpu": "arm" }, "sha512-gq84vM1a1oEehXo27YCDzGVcxPsZDI1yswZwz2Da1/cbnWtrL16XZZnz0G/+gIU8edtHpfjxq5c+vWEHqJfWoQ=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.77.0", "", { "os": "linux", "cpu": "arm" }, "sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.69.0", "", { "os": "linux", "cpu": "arm" }, "sha512-kIqEa98JQ0VRyrcncxA417m2AzasqTlD+FyVT1AksjvjkqQcvm7pBWYvoW3/mpyOP2XYvi5nSCCTIe6De1yu5g=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.77.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.69.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j+xYiXozxGWx2cpjCrwwGR4awTxPFsRv3JZrv23RCogEPMc4R7UqjHW47p/RG0aRlbWiROCJ8coUfCwy0dvzHA=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.77.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.69.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-xEPpNppTfN1l/nM7gYSf9iocscu/as+p/7vxkLeLEKnYU+09Dm+5V6IhDYDh+Uz6FajEupWwCLt5SOG0y1PCKg=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.77.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.69.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Ug0+eU7HJBlek+SjklYH62IlOMirEJsdxpihH0kSqX0XdrDD4NdHpQc10fK1JC35yn6KrrcN+uYzlHD38XAf8Q=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.77.0", "", { "os": "linux", "cpu": "none" }, "sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.69.0", "", { "os": "linux", "cpu": "none" }, "sha512-iEyI3GIg0l/s3G4qy2TlaaWKdzj4PJJStwtlocpDTC00PY9hZueotf6OKUj9+yfQh0lrpBW/pLMgTztbAHKJEg=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.77.0", "", { "os": "linux", "cpu": "none" }, "sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.69.0", "", { "os": "linux", "cpu": "none" }, "sha512-NjHjpiI4WIKSMwuoJSZi5VToPeoYOS1FR52HLIDG6lidMdqquusgtODb4iLk0+lb1q3Z0nv2/aPRcC/olmpQGg=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.77.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.69.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Ai/prDewoItkDXbp38gwGZi41DycZbUTZJ3UidwoHgQC0/DaqC2TGdtBTQLJ6hSD+SAxASzh8+/eSBPmxfOacA=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.77.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.69.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Gt3KHgp46mRKz4sJeaASmKvD8ayXookRw07RMf+NowhEztGGDZ7VrXpoW96XuKJLjFukWizOFVNjmYb/u7caNQ=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.77.0", "", { "os": "linux", "cpu": "x64" }, "sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.69.0", "", { "os": "linux", "cpu": "x64" }, "sha512-7tQhJ2+p/oHv1zcfnjYI7YVzC/7iBaVOfIvFYtxdJ5F45mWgEdrCyXZXZGfiLey5t/5JhOhsaMnnv1kAzckd7g=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.77.0", "", { "os": "none", "cpu": "arm64" }, "sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.69.0", "", { "os": "none", "cpu": "arm64" }, "sha512-vmWz6TKp/3hfA4lksR0zHBv/6xuX1jhym6eqOjdH2DXsDDHZWcp2f0KG0VCAnlVbIrjk29G4wAWMXb/Hn1YobA=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.77.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.69.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-9RExaLgmaw6IoIkU9cTpT71mLfI0xZ86iZH8x518LVsOkjquJMYqb9P7KpC8lgd1t0Dxs41p2pxynq4XR3Ttzw=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.77.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.69.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-1907kRPF8/PrcIw1E7LMs9JbVrpgnt/MvFdss3an8oDkYNAACXzTntV3t3869ZZhMZxb2AzRGbz1pA/jdFatXA=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.77.0", "", { "os": "win32", "cpu": "x64" }, "sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.69.0", "", { "os": "win32", "cpu": "x64" }, "sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA=="], "@pascal-app/capture-protocol": ["@pascal-app/capture-protocol@workspace:packages/capture-protocol"], @@ -771,7 +777,7 @@ "@pascal-app/ifc-converter": ["@pascal-app/ifc-converter@workspace:packages/ifc-converter"], - "@pascal-app/lingo": ["@pascal-app/lingo@0.2.1", "", { "peerDependencies": { "react": "^19" }, "optionalPeers": ["react"] }, "sha512-Y6Nmb4vLSMp/dIdKABc7GjdTdB6yvUyBg95ySlThMz6zKrJjpVG0utexY4cnmWVPkGNSKOFotiHw8UJiQMUVnw=="], + "@pascal-app/lingo": ["@pascal-app/lingo@0.2.0", "", { "peerDependencies": { "react": "^19" }, "optionalPeers": ["react"] }, "sha512-Ws+Utm23SmDbMB0Jc7joIp4KPkXhs4Z1boUcW9dl8nC3ATJz+a50F7/MyVTbE3QaL5Fr+YwNfsiOMxrKdhwPhA=="], "@pascal-app/mcp": ["@pascal-app/mcp@workspace:packages/mcp"], @@ -787,93 +793,93 @@ "@pascal/typescript-config": ["@pascal/typescript-config@workspace:tooling/typescript"], - "@preact/signals": ["@preact/signals@2.11.1", "", { "dependencies": { "@preact/signals-core": "^1.14.4" }, "peerDependencies": { "preact": ">= 10.25.0 || >=11.0.0-0" } }, "sha512-uYoD+USkacTNU02kfCBkJEV7xabKTmA78W5pnT2GymsuGEC9n/ZO+UT4S96l0dIL6KLDk77VJyUFuOMBvftVHg=="], + "@preact/signals": ["@preact/signals@2.9.1", "", { "dependencies": { "@preact/signals-core": "^1.14.0" }, "peerDependencies": { "preact": ">= 10.25.0 || >=11.0.0-0" } }, "sha512-xVqN8mJjbSN5IB/8Ubmd9NN+Ew6zJswoRxrjZbH3YsgkMshFeO6d8zxEFpHRTq9GJZx7cnPs2CnCpFqtGXGNsw=="], - "@preact/signals-core": ["@preact/signals-core@1.14.4", "", {}, "sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA=="], + "@preact/signals-core": ["@preact/signals-core@1.14.2", "", {}, "sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A=="], - "@radix-ui/number": ["@radix-ui/number@1.1.3", "", {}, "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA=="], + "@radix-ui/number": ["@radix-ui/number@1.1.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.4", "", {}, "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ=="], - "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dialog": "1.1.23", "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VAYOiQRqj3GPpYJE0I9J+X8Ip05cyVlNdKOFeiGS2Ou1HHGfpl0BxOyZm6nmVDyU+W+NF3/XLzmjHmVGydhwgA=="], + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dialog": "1.1.16", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPaIgo0mxYlvcFaM9jB2Uot9TjGXMuAPEvrc6BOLeV+I5U8s1dkIoouYaa6lmSfc5SPMo5x5djOTOTvaigdGMQ=="], - "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA=="], + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yqHW5WQ/cTpU/un7dqqIKNy2iRU8BC0JB78PEzTfCCYvZu1U6W9KwObAniMk9nhSfyotKPQTYaUD/HB0f5muig=="], - "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.15", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.9", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zuSVi7ziP7uQRqc+yGxsKJfNkdyHv3ZKDaHe0gzg4dRgws96TPKWIiz84tVHP4GEcEl8bC0mdt17NkcxaJHmaQ=="], - "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.5", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA=="], + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="], - "@radix-ui/react-context": ["@radix-ui/react-context@1.2.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA=="], + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg=="], - "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.0", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-menu": "2.1.17", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-d7CouXhAW+CGmFOqmB+IEvd3E9GcaqfgvfjCc3hfulp2pkaUCEVEGa0SN5nNWYA+IvQ6g1Pt+S5dpNn1AoY9hg=="], - "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.9", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-l9ok83YBclEZhbjgzt76Hw733e6cvRKPNgO6GJ/IETlufXG9p+fRu2wlvpImQvR6xdJ8h7J8J2DBvsPEiEsKMw=="], - "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg=="], + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="], - "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-effect-event": "0.0.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-escape-keydown": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MhoruH6xEzsbvOmo4TNgMfmtvRGyDZw4MDSdf4ybMHfezjqwzv6hyd4lsMzBp8K9Sn6sGzCF62x1I7BYUECXOg=="], - "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-menu": "2.1.24", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g=="], + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-menu": "2.1.17", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-S6b3Jm57sY5EdDyOMLkacbB0qMnKhy1RCKZCt795ZkmtUOAvojYIZ5p7dXHIh5Cyr3jCLLI5/g64V3FKLudZmw=="], - "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.6", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ=="], + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q=="], - "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.16", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ=="], + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.9", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9Se8t+Zry+1rEOL7Y6l/4ANYU/TOtAtf8O2fKdwLltcaMcm6kOqYGbzO4tMFQ0bvzO920pRAoHpFZ4W85S3keQ=="], - "@radix-ui/react-id": ["@radix-ui/react-id@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="], - "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.24", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.9", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.0", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-roving-focus": "1.1.12", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-fmbNnFyf+JYCN0DhhWnEdUTDnZD1mXaPQWivdsPIb8oOSbARfD3LIQJbLCG8a8QLCwoMxiJ7GVPIFcC8Dw8v2Q=="], - "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.23", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.9", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.0", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-8brVpAU5Uq7Bh0c8EFc4ZTf2JJTYn0o+1L+CUJB3UYIOkTjKGMgoHvduylrahdmNlr3DfH0rFq2DrbNZXgaspw=="], - "@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.7", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-rect": "1.1.4", "@radix-ui/react-use-size": "1.1.4", "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.0", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-rect": "1.1.2", "@radix-ui/react-use-size": "1.1.2", "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9PB589e1aWZbrlFUHdz6WiPCL+xLZHQFX7oibqG/6Q0SwOkxDyQX9W/cyPa+sAPPKuC8cpLCpRczE5a/1DiwVQ=="], - "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.17", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ=="], + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UEytdjgEh2tJGgD/gZK4FUx6t1rNIlM3U0DENhSrG7I75FGm1DnaDuVUWF1pWAWUwGmn1sCJ1VGHn8LhN1aTOw=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.10", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.6", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.10", "", { "dependencies": { "@radix-ui/react-slot": "1.3.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.5", "", { "dependencies": { "@radix-ui/react-slot": "1.2.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zifXeB8Y88qCYx8PLZ5oQb32KwZub+s925mMoZsBBq9KUQqWKkREubTfs6ASjRPPBe7Jt9O8OHH89+95VG+grA=="], - "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-is-hydrated": "0.1.3", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FvgPt1bRmg8Xt2QpF7NUZW3dE0ZQHGm41dAdgT2J2GJPoIXz+9Em3NobAxf4fupcxhgHu03E5CRiU2MWvObXyg=="], - "@radix-ui/react-select": ["@radix-ui/react-select@2.3.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.1.16", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg=="], + "@radix-ui/react-select": ["@radix-ui/react-select@2.3.0", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.9", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.0", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.5", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mENc7WpJvJcW8hlMpzfFcHcEhTvYS5JMBmi9HVC1Q00uhBwML086MHYUV8QQdQv6lcu0Wg8dzd1RB8AFADcG/g=="], - "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.15", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw=="], + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-gvgW+JV/Mbjj6darztTetnmElpQEzZrXpJvfj+dOxNAxiyHEAyUvEjjl4zxblvmjmKmi3jfPoy7ZdxzCuUBJSA=="], - "@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.7", "", { "dependencies": { "@radix-ui/number": "1.1.3", "@radix-ui/primitive": "1.1.7", "@radix-ui/react-collection": "1.1.15", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-use-previous": "1.1.4", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg=="], + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.0", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-RHcPlLOThRJM51DSIC33ZnpDEBYhyEFroVWkd2P54PGGjkmAt14RboYUU9E1MFst666zFHM0tGtWvMjSOtU1pw=="], - "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rCMO3QsIVKv5JTY5CVbo2MvO77SpEqqYc8AvRE7OWqRDOIqAKjsp+DrmnY9uc8NPdxB5E2z47HTYGeE2+NTptg=="], - "@radix-ui/react-switch": ["@radix-ui/react-switch@1.3.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-size": "1.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.3.0", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-GP1EZwhoZO/GGnhM1P5/2Vpm8iN8EnngyU0oezn2l78kN8tj25pyrvjIaT7azBhK615KSt+P2w39y57YV5jVkA=="], - "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.21", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-direction": "1.1.4", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-roving-focus": "1.1.19", "@radix-ui/react-use-controllable-state": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-roving-focus": "1.1.12", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-D5jwp9JNuwDeCw3CYD2Fz+sSHo0droQjC8u75dJHe4aWr5q6yBiXZU+hurXnKudRgEpUkD5TsI6bjHPo5ThUxA=="], - "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.19", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-popper": "1.3.7", "@radix-ui/react-portal": "1.1.17", "@radix-ui/react-presence": "1.1.10", "@radix-ui/react-primitive": "2.1.10", "@radix-ui/react-slot": "1.3.3", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "@radix-ui/react-visually-hidden": "1.2.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.9", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.0", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-visually-hidden": "1.2.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-u6F9MmTtBSLkiXNVDrtB/yPCZarM9smNswC24YYLV/M+bth6J3Gs3vlJezEoFwKZvPvxhCpUYdUnOsNG/0XOlA=="], - "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="], - "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ=="], + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.3", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA=="], - "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.5", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg=="], + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.3", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA=="], - "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw=="], + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.2", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw=="], - "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="], - "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg=="], + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="], - "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.4", "", { "dependencies": { "@radix-ui/rect": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ=="], + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.2", "", { "dependencies": { "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw=="], - "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw=="], + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w=="], - "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.10" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ=="], + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.5", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.5" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tPcHNI3FajdDBFpl/Ez1m2WL0ufJqBKyHxMDBvKitopamK36WwBGOMicuMEZKkM5Wce41QxUyv6BsiqfrWBiGg=="], - "@radix-ui/rect": ["@radix-ui/rect@1.1.3", "", {}, "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw=="], + "@radix-ui/rect": ["@radix-ui/rect@1.1.2", "", {}, "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA=="], "@react-grab/cli": ["@react-grab/cli@0.1.50", "", { "dependencies": { "agent-install": "^0.0.6", "commander": "^14.0.3", "ignore": "^7.0.5", "ora": "^9.4.0", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "tinyexec": "^1.1.2" }, "bin": { "react-grab": "bin/cli.js" } }, "sha512-Px/Hwhhyk2PubCA4ZaRFsfvwxhbxXsetJyvqC6aFFi8WhJhA+oVC33aTzuAeWmM3fhb4/8ce8YsHXI1d6ChcKg=="], - "@react-three/drei": ["@react-three/drei@10.7.8", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-rJXyuzLm2Xq0kafHuR47ajDGbOe/pEhzIr4m8E8zwzQs0iNjloFDqBwRhrXmP/w+onLeYyN3EYPFW/cwWK/4yA=="], + "@react-three/drei": ["@react-three/drei@10.7.7", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ=="], - "@react-three/fiber": ["@react-three/fiber@9.7.0", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-use-measure": "^2.1.7", "scheduler": "^0.27.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": ">=19 <19.3", "react-dom": ">=19 <19.3", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-EWm9FwcaOZQu/ExFW5rggoCMM1NJet5YbxVxKaOE+KSncrjU0Wx7017qSyGFvupviK89nMYGCWU3BIK4dI1clw=="], + "@react-three/fiber": ["@react-three/fiber@9.6.1", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-use-measure": "^2.1.7", "scheduler": "^0.27.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": ">=19 <19.3", "react-dom": ">=19 <19.3", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-zF0rsKcVYpcJwbFEnv2HkHX9cvOEgsfQo/X8lwmR2dn13S4qEQJXir9fxf5js2LQFoXqxOY7MDkOkYx2uZ4gSg=="], "@repo/eslint-config": ["@repo/eslint-config@workspace:packages/eslint-config"], @@ -883,75 +889,69 @@ "@rollup/pluginutils": ["@rollup/pluginutils@5.4.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg=="], - "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], - - "@sentry/conventions": ["@sentry/conventions@0.16.0", "", {}, "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ=="], + "@sentry-internal/server-utils": ["@sentry-internal/server-utils@10.57.0", "", { "dependencies": { "@sentry/core": "10.57.0" } }, "sha512-Qu8ETmX/ITzteG7Im46b9HOxKKzeaIeqNvftaIlFURu1RUQdHbtGerS7QOmXzwnhuqNGNeiCQYkduB798IfRqA=="], - "@sentry/core": ["@sentry/core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0" } }, "sha512-ozhCTDqg89oB4XmWfAwuHshABpvT7AkRpaPnogopPfMAaI61G1t8EKCJ4W7aum8JSBonlfyjPCyW5oYZFm0KvA=="], + "@sentry/core": ["@sentry/core@10.57.0", "", {}, "sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg=="], - "@sentry/node": ["@sentry/node@10.70.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/instrumentation": "^0.220.0", "@opentelemetry/sdk-trace-base": "^2.9.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/node-core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "@sentry/server-utils": "10.70.0", "import-in-the-middle": "^3.0.0" } }, "sha512-SPOOVxmKTVIEtqvOKkQT163e/pOwucjS7OPsCHyRs8sFR4nfBNu0EThplyqnvqd5BWBMTPH6WTBQfo+QWHV+HA=="], + "@sentry/node": ["@sentry/node@10.57.0", "", { "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/core": "^2.6.1", "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", "@sentry-internal/server-utils": "10.57.0", "@sentry/core": "10.57.0", "@sentry/node-core": "10.57.0", "@sentry/opentelemetry": "10.57.0", "import-in-the-middle": "^3.0.0" } }, "sha512-7KEStrJ97wPf1fA5nU5ONeTTcIIlh7oT8OMffEVA1PXmlhFoXhcQZVzr4rM+zj9tfMWT01og5Ng/Grgh3dN+FA=="], - "@sentry/node-core": ["@sentry/node-core@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "@sentry/opentelemetry": "10.70.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base"] }, "sha512-oPOEVVNxv5WHtckx2i06Wi9FLWyvOg/1DUeX732jZ4iqT2nupINaMH4nF4f4kSvUThFnxkFSRQxwqOxgzMKhKA=="], + "@sentry/node-core": ["@sentry/node-core@10.57.0", "", { "dependencies": { "@sentry/core": "10.57.0", "@sentry/opentelemetry": "10.57.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base", "@opentelemetry/semantic-conventions"] }, "sha512-2v2IF6MfTiu7pimWEq2rYhZsmlwyNbs3bHUsrYFPeP/Rpa6ObDuUWPdVEzJjfyK+AqqYZYxZdV0l3+B13kTEmQ=="], - "@sentry/opentelemetry": ["@sentry/opentelemetry@10.70.0", "", { "dependencies": { "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" } }, "sha512-UNV/2tqypcUK6FDzerAsFJn1Km/c4VZCYkUZDNbnV5S0cwAq2BYKMo4M5vovaLDBQlxA+Wk9ovbxi5wYjjl9fw=="], + "@sentry/opentelemetry": ["@sentry/opentelemetry@10.57.0", "", { "dependencies": { "@sentry/core": "10.57.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" } }, "sha512-iwRz8cEK0GOISG34aJRO8GdYOk3nfpuT6dT2GDQrxw8f7JjkJKx9LPU8MaenOFa4MhY+Z02hI6NNcrbsoI3cXg=="], - "@sentry/server-utils": ["@sentry/server-utils@10.70.0", "", { "dependencies": { "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", "@apm-js-collab/tracing-hooks": "^0.13.0", "@sentry/conventions": "^0.16.0", "@sentry/core": "10.70.0", "meriyah": "^6.1.4" } }, "sha512-rzegZjMFFgCp3o+N8+XU13rfSvz4B+f8rU0ijBGrQcHdMNyfsFDTu1UTm262JofmrV2u+s+D0u0vFTnqtOGkbA=="], - - "@shaderfrog/glsl-parser": ["@shaderfrog/glsl-parser@7.0.1", "", {}, "sha512-8mpfsoPeRhesY3pOrzNZBL8uG6N5GVX1EHLBYbd4gzKs+c7vaEIqpTNK5VrffU33qQN4cwpP2v3u4aPPBU32sw=="], - - "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.3.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.3" } }, "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg=="], + "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.3", "@tailwindcss/oxide-darwin-arm64": "4.3.3", "@tailwindcss/oxide-darwin-x64": "4.3.3", "@tailwindcss/oxide-freebsd-x64": "4.3.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", "@tailwindcss/oxide-linux-x64-musl": "4.3.3", "@tailwindcss/oxide-wasm32-wasi": "4.3.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.3", "", { "os": "android", "cpu": "arm64" }, "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="], "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="], "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="], "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="], "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.3", "", { "dependencies": { "@emnapi/core": "^1.11.1", "@emnapi/runtime": "^1.11.1", "@emnapi/wasi-threads": "^1.2.2", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="], - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.3", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "postcss": "^8.5.16", "tailwindcss": "4.3.3" } }, "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.0", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "postcss": "^8.5.10", "tailwindcss": "4.3.0" } }, "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w=="], - "@turbo/darwin-64": ["@turbo/darwin-64@2.10.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-v3R+1R/Ysozyo+p7Ri8MCIbndOvYt3DgPFrGLhrhQHfvyvbxyH3WyJj+A/2JTNmNleuAlh3JUyCV0iSVHIONTA=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.9.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-io5jn5RDeU+9YV78rWhwG++HD/OZ/Lxg1sg93+jDGKQNP3UDxY6RX2dmarbCILhNxNuAM8FH3WgGMY9E96Mf8w=="], - "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.10.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R0a0CvGAeYYsBgPIgFNB3agGXh6qukjduNhFlwVVX1Ss2IdBJLXmgjytNGmo084bLKS0B6UdLRwKhXMHKKaObQ=="], + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-83YZTYmN2sxFWf2LTMOwqbOvR3qZMa/TSFwnB6BHVBbIWyoPPe+TAdSTd8KevEx8ml8KkycJ/9A70DFVReyUww=="], - "@turbo/linux-64": ["@turbo/linux-64@2.10.11", "", { "os": [ "linux", "android", ], "cpu": "x64" }, "sha512-dGlY2vg7jpsLjGS1bf9sD/cw1sGMAYbeHGQKGRFxd5Zaj+Ufbj8cNXl/vIit8ueCU97zhL/znn60ZV5iSfZAxw=="], + "@turbo/linux-64": ["@turbo/linux-64@2.9.17", "", { "os": "linux", "cpu": "x64" }, "sha512-teKfwJg0zSC+C2ZSOsX3VnAJGVgcN+pgKNmnGWzcpXQ9eIkAQtYP+getrQ2f1Tw/ePudnreQhq8tVP8S73Vy6Q=="], - "@turbo/linux-arm64": ["@turbo/linux-arm64@2.10.11", "", { "os": [ "linux", "android", ], "cpu": "arm64" }, "sha512-eSP9+jjsSCBs2x0QpJZlp49dSD1EIMwXH7PsMIhdWk7w6IThhuKJ+jL95JQ2IW7tRjRmdh8gKcKQtrHLD5R5lA=="], + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-mqO36x2CNtJ9CCbEf5xOqH662tVSc1wB0mxh7dopBpgXg0fEifdzwX0IEAUW1WUAaNH986L7iEUUgw3HNqUWgg=="], - "@turbo/windows-64": ["@turbo/windows-64@2.10.11", "", { "os": "win32", "cpu": "x64" }, "sha512-4aD7edogJ8arK8DOyvjTI2KKwmchD5M/WM4BZgidrtFf7aSgn8Ce2rJnDwmriw980c2cKlHnhXtlGy38VtKB8g=="], + "@turbo/windows-64": ["@turbo/windows-64@2.9.17", "", { "os": "win32", "cpu": "x64" }, "sha512-jbyoNePufyMoSSrvVr+/mglcjmya/MOgoIrSHPr67iZ1VFgrlMQXHXtptR2lR48gi+86b1XBvsviJZ9A7zrydg=="], - "@turbo/windows-arm64": ["@turbo/windows-arm64@2.10.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-m8tJkIrTrbQ9O1uHxV0GUq623Zg1678xGna8eMsy4KbygUX/wVFgdZDYV/AxyoyaW/U7nyKoBvaDVwm22p9xqA=="], + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-+ql0wYc99Y2AMvyHCcC/P+xtyV4nz522L+C9HDnyi7ryHXBGM+ZjBP28M7SLBGMDImgpN8sk2szpgbvreMeXVA=="], "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], "@types/blob-stream": ["@types/blob-stream@0.1.33", "", { "dependencies": { "@types/node": "*" } }, "sha512-HNHZ1S6W7F8PhxdyAastunpUC8cAZim78UIfqbL79gLzylp8EZep68yxAh11hTRoEvsqHAg/MECgmKF8+V0HzQ=="], - "@types/bun": ["@types/bun@1.4.0", "", { "dependencies": { "bun-types": "1.4.0" } }, "sha512-K+lZULY23vRgK/CfTjFIV+tyifaNdSMlPh9j+6mQ/cLfpOznLyAuzgV/JQysyECpkBQLVMSyvjlr2fBUSA9wFQ=="], + "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], "@types/draco3d": ["@types/draco3d@1.4.10", "", {}, "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw=="], @@ -965,7 +965,7 @@ "@types/ndarray": ["@types/ndarray@1.0.14", "", {}, "sha512-oANmFZMnFQvb219SSBIhI1Ih/r4CvHDOzkWyJS/XRqkMrGH5/kaPSA1hQhdIBzouaE+5KpE/f5ylI9cujmckQg=="], - "@types/node": ["@types/node@22.20.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q=="], + "@types/node": ["@types/node@22.19.20", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw=="], "@types/offscreencanvas": ["@types/offscreencanvas@2019.7.3", "", {}, "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A=="], @@ -983,25 +983,27 @@ "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.67.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.67.0", "@typescript-eslint/type-utils": "8.67.0", "@typescript-eslint/utils": "8.67.0", "@typescript-eslint/visitor-keys": "8.67.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.67.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.61.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/type-utils": "8.61.0", "@typescript-eslint/utils": "8.61.0", "@typescript-eslint/visitor-keys": "8.61.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.61.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.67.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.67.0", "@typescript-eslint/types": "8.67.0", "@typescript-eslint/typescript-estree": "8.67.0", "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.61.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/types": "8.61.0", "@typescript-eslint/typescript-estree": "8.61.0", "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.67.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.67.0", "@typescript-eslint/types": "^8.67.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.61.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.61.0", "@typescript-eslint/types": "^8.61.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.67.0", "", { "dependencies": { "@typescript-eslint/types": "8.67.0", "@typescript-eslint/visitor-keys": "8.67.0" } }, "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.61.0", "", { "dependencies": { "@typescript-eslint/types": "8.61.0", "@typescript-eslint/visitor-keys": "8.61.0" } }, "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.67.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.61.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.67.0", "", { "dependencies": { "@typescript-eslint/types": "8.67.0", "@typescript-eslint/typescript-estree": "8.67.0", "@typescript-eslint/utils": "8.67.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.61.0", "", { "dependencies": { "@typescript-eslint/types": "8.61.0", "@typescript-eslint/typescript-estree": "8.61.0", "@typescript-eslint/utils": "8.61.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.67.0", "", {}, "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.61.0", "", {}, "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.67.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.67.0", "@typescript-eslint/tsconfig-utils": "8.67.0", "@typescript-eslint/types": "8.67.0", "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.61.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.61.0", "@typescript-eslint/tsconfig-utils": "8.61.0", "@typescript-eslint/types": "8.61.0", "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.67.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.67.0", "@typescript-eslint/types": "8.67.0", "@typescript-eslint/typescript-estree": "8.67.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.61.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/types": "8.61.0", "@typescript-eslint/typescript-estree": "8.61.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.67.0", "", { "dependencies": { "@typescript-eslint/types": "8.67.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.61.0", "", { "dependencies": { "@typescript-eslint/types": "8.61.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ=="], "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260624.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260624.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260624.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260624.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260624.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260624.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260624.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260624.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-ogwfNo1xuAutOF8RbTCo3Ut0q/65u2ucOeHizi6O14q+3vnelNS+u8qVC2QWXubMcwtuN5E9cbfPslvGC4kdwA=="], @@ -1069,7 +1071,9 @@ "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], @@ -1081,9 +1085,7 @@ "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], - - "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -1107,8 +1109,6 @@ "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], - "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], "atomically": ["atomically@2.1.1", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ=="], @@ -1119,7 +1119,7 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.11.17", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-KAUDn1OSS0fmPlGO+NOUMRcOQ/b/shUBH3OgkG73mPgdf+JD/BQ6fHboGxNOxnUmlwcq+lLq3dTkayRPuSfXwg=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.35", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg=="], "bidi-js": ["bidi-js@1.0.3", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw=="], @@ -1129,9 +1129,9 @@ "blob-stream": ["blob-stream@0.1.3", "", { "dependencies": { "blob": "0.0.4" } }, "sha512-xXwyhgVmPsFVFFvtM5P0syI17/oae+MIjLn5jGhuD86mmSJ61EWMWmbPrV/0+bdcH9jQ2CzIhmTQKNUJL7IPog=="], - "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], - "brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="], + "brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -1139,11 +1139,11 @@ "browserify-zlib": ["browserify-zlib@0.2.0", "", { "dependencies": { "pako": "~1.0.5" } }, "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA=="], - "browserslist": ["browserslist@4.28.8", "", { "dependencies": { "baseline-browser-mapping": "^2.11.12", "caniuse-lite": "^1.0.30001809", "electron-to-chromium": "^1.5.402", "node-releases": "^2.0.53", "update-browserslist-db": "^1.3.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA=="], + "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - "bun-types": ["bun-types@1.4.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-iIKw23BspnQQYd3prITOBxeUsxBHnwzX6YJfGMuNOZzeNcMmVqzIIVGRm1l69ogaPQmb4wB6BN8mA5bE9YuC5Q=="], + "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -1157,13 +1157,13 @@ "camera-controls": ["camera-controls@3.1.2", "", { "peerDependencies": { "three": ">=0.126.1" } }, "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001809", "", {}, "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001797", "", {}, "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "citty": ["citty@0.2.2", "", {}, "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w=="], - "cjs-module-lexer": ["cjs-module-lexer@2.2.1", "", {}, "sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q=="], + "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], @@ -1171,8 +1171,6 @@ "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], - "cli-truncate": ["cli-truncate@6.1.1", "", { "dependencies": { "slice-ansi": "^9.0.0", "string-width": "^8.2.0" } }, "sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw=="], - "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], @@ -1221,7 +1219,7 @@ "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "dedent": ["dedent@1.7.2", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA=="], @@ -1235,7 +1233,7 @@ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], - "deslop-js": ["deslop-js@0.9.12", "", { "dependencies": { "@oxc-project/types": "^0.143.0", "fast-glob": "^3.3.3", "minimatch": "^10.2.5", "oxc-parser": "^0.143.0", "oxc-resolver": "^11.24.2", "typescript": ">=5.0.4 <6" } }, "sha512-Ku6Zngzmu4EISb58WUkRKZytfgWjJ18Cic7lb4wl+/BF0tHWRvpBOLlA0FP35r82mV45Y72AK3RPC1Nw0GLbIw=="], + "deslop-js": ["deslop-js@0.0.21", "", { "dependencies": { "@oxc-project/types": "^0.132.0", "fast-glob": "^3.3.3", "minimatch": "^10.2.5", "oxc-parser": "^0.132.0", "oxc-resolver": "^11.19.1", "typescript": "^6.0.3" } }, "sha512-1fYusMl4tDaQ/xdHFtLfDe8kFrEeU0Vu0Pfiy2k/Gd4HSqYlQj1Z7iRqldNneRyuCzNMhwNBvhaL07Urbh5VOA=="], "detect-gpu": ["detect-gpu@5.0.70", "", { "dependencies": { "webgl-constants": "^1.1.1" } }, "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w=="], @@ -1247,7 +1245,7 @@ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dot-prop": ["dot-prop@10.2.0", "", { "dependencies": { "type-fest": "^5.0.0" } }, "sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw=="], + "dot-prop": ["dot-prop@10.1.0", "", { "dependencies": { "type-fest": "^5.0.0" } }, "sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q=="], "dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], @@ -1263,29 +1261,23 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.412", "", {}, "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA=="], + "effect": ["effect@4.0.0-beta.70", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "sha512-8AwGTRiNriirHGEYHrOS0E9fzdhIqCdZjiHP1YXmNo2UyPGS43ILsymsSHT7V0DJS+8dvlKq2RxnrDBUhDNZHg=="], - "empathic": ["empathic@2.0.1", "", {}, "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q=="], + "electron-to-chromium": ["electron-to-chromium@1.5.370", "", {}, "sha512-D5tSHJReAb/Kf3Hu9F/GO4lJuSWzEWHwvQ/kKSUP7pimNgvxkSKj+gUQhHpKKACwrin7rS3byU7IxreF56rl5g=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="], + "enhanced-resolve": ["enhanced-resolve@5.23.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA=="], "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], - "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], - "es-abstract": ["es-abstract@1.24.2", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg=="], - "es-abstract-get": ["es-abstract-get@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "es-object-atoms": "^1.1.2", "is-callable": "^1.2.7", "object-inspect": "^1.13.4" } }, "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg=="], - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-iterator-helpers": ["es-iterator-helpers@1.4.0", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "math-intrinsics": "^1.1.0" } }, "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q=="], - - "es-module-lexer": ["es-module-lexer@2.3.2", "", {}, "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw=="], + "es-iterator-helpers": ["es-iterator-helpers@1.3.2", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "math-intrinsics": "^1.1.0" } }, "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw=="], "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], @@ -1293,7 +1285,7 @@ "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], - "es-to-primitive": ["es-to-primitive@1.3.4", "", { "dependencies": { "es-abstract-get": "^1.0.0", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "is-callable": "^1.2.7", "is-date-object": "^1.1.0", "is-symbol": "^1.1.1" } }, "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw=="], + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], "esbuild-wasm": ["esbuild-wasm@0.27.7", "", { "bin": { "esbuild": "bin/esbuild" } }, "sha512-1k03e2/tGz+sLz3/xzoZmUsIqtaGIvJa8k4UqUeqCUry83nHmlxQYZUUES0WBFUYilSQUf7nDUGAciIIklljSg=="], @@ -1303,7 +1295,7 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@9.39.5", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.6", "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw=="], + "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], @@ -1313,7 +1305,7 @@ "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], - "eslint-plugin-turbo": ["eslint-plugin-turbo@2.10.11", "", { "dependencies": { "dotenv": "16.0.3" }, "peerDependencies": { "eslint": ">6.6.0", "turbo": ">2.0.0" } }, "sha512-O8EyyiHpP6sMYVweD1Ix+l9ub21rW3NYE+/VPSuhm2WhPW3AF6mOdlkuJofHA2RMHt6zR3zoiUA4AF15dQPHNA=="], + "eslint-plugin-turbo": ["eslint-plugin-turbo@2.9.17", "", { "dependencies": { "dotenv": "16.0.3" }, "peerDependencies": { "eslint": ">6.6.0", "turbo": ">2.0.0" } }, "sha512-M64pKjQjCKAb3Oz/xptnCFmsBO+xREs9hOrv1dMCyYtRHtfrXv6OCa6+g4RQV8/2dZb980yBMmBpNmMpOEDCeA=="], "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], @@ -1337,17 +1329,17 @@ "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], - "eventsource-parser": ["eventsource-parser@3.1.1", "", {}, "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ=="], - - "execa": ["execa@10.0.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "figures": "^6.1.0", "get-stream": "^9.0.1", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.3.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "which-command": "^0.1.0", "yoctocolors": "^2.1.2" } }, "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw=="], + "eventsource-parser": ["eventsource-parser@3.1.0", "", {}, "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg=="], "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], - "express-rate-limit": ["express-rate-limit@8.6.2", "", { "dependencies": { "debug": "^4.4.3", "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A=="], + "express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="], + + "fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], @@ -1357,7 +1349,7 @@ "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], - "fast-uri": ["fast-uri@3.1.5", "", {}, "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw=="], + "fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="], "fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="], @@ -1371,21 +1363,19 @@ "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], - "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="], - "find-workspaces": ["find-workspaces@0.3.1", "", { "dependencies": { "fast-glob": "^3.3.2", "pkg-types": "^1.0.3", "yaml": "^2.3.4" } }, "sha512-UDkGILGJSA1LN5Aa7McxCid4sqW3/e+UYsVwyxki3dDT0F8+ym0rAfnCkEfkL0rO7M+8/mvkim4t/s3IPHmg+w=="], + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - "flatted": ["flatted@3.4.4", "", {}, "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q=="], + "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], "fontkit": ["fontkit@2.0.4", "", { "dependencies": { "@swc/helpers": "^0.5.12", "brotli": "^1.3.2", "clone": "^2.1.2", "dfa": "^1.2.0", "fast-deep-equal": "^3.1.3", "restructure": "^3.0.0", "tiny-inflate": "^1.0.3", "unicode-properties": "^1.4.0", "unicode-trie": "^2.0.0" } }, "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g=="], @@ -1393,13 +1383,13 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - "framer-motion": ["framer-motion@12.43.0", "", { "dependencies": { "motion-dom": "^12.43.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g=="], + "framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "^12.40.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="], "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "function.prototype.name": ["function.prototype.name@1.2.0", "", { "dependencies": { "call-bind": "^1.0.9", "call-bound": "^1.0.4", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2", "hasown": "^2.0.4", "is-callable": "^1.2.7", "is-document.all": "^1.0.0" } }, "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew=="], + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], @@ -1417,10 +1407,10 @@ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], - "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="], @@ -1451,19 +1441,17 @@ "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], - "hls.js": ["hls.js@1.7.1", "", {}, "sha512-DlzIkeBAS9IIQ432k3BUf3HlwbsR0+trB1i2lDdN2gUkNkrehFurh0/48M5c1/EjlDkdGng1gwZIpwyPxvdZ/g=="], + "hls.js": ["hls.js@1.6.16", "", {}, "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA=="], - "hono": ["hono@4.13.3", "", {}, "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw=="], + "hono": ["hono@4.12.25", "", {}, "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ=="], "howler": ["howler@2.2.4", "", {}, "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w=="], "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], - "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], - - "idb-keyval": ["idb-keyval@6.3.0", "", {}, "sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow=="], + "idb-keyval": ["idb-keyval@6.2.5", "", {}, "sha512-eKQkTnS0relYsSOYomx8ozIbmdsQCKUdhyuIaQ2DZgKuaxtyQQMkyD/wlnQN32pO3yutN1b1L8uqwcDKaJd7/Q=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -1475,17 +1463,19 @@ "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "import-in-the-middle": ["import-in-the-middle@3.3.3", "", { "dependencies": { "cjs-module-lexer": "^2.2.0", "es-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-AiohS3H80sXO6owEltjGX+glb7qXaDhBoJb9XcQVH4UI207xu/bDLUcadVKp7Qe576reg9yr/PXZjV5qx8gfbA=="], + "import-in-the-middle": ["import-in-the-middle@3.0.2", "", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-LGLYRl0A2gtyUJb2WDliBHmk6TtlHwdDjxonacZ8QrEs/ZW+YDgNv2QAfjRQWpS8HqvNcq6GGnN6jrOa5FysDQ=="], "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "ini": ["ini@7.0.0", "", {}, "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w=="], + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], "iota-array": ["iota-array@1.0.0", "", {}, "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA=="], - "ip-address": ["ip-address@10.5.0", "", {}, "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g=="], + "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -1507,14 +1497,10 @@ "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], - "is-document.all": ["is-document.all@1.0.0", "", { "dependencies": { "call-bound": "^1.0.4" } }, "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g=="], - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], - "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], @@ -1529,8 +1515,6 @@ "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], - "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], @@ -1539,8 +1523,6 @@ "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], - "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], @@ -1567,13 +1549,13 @@ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], - "jose": ["jose@6.2.9", "", {}, "sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA=="], + "jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], "js-md5": ["js-md5@0.8.3", "", {}, "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.3.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ=="], + "js-yaml": ["js-yaml@4.2.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -1597,6 +1579,8 @@ "ktx-parse": ["ktx-parse@1.1.0", "", {}, "sha512-mKp3y+FaYgR7mXWAbyyzpa/r1zDWeaunH+INJO4fou3hb45XuNSwar+7llrRyvpMWafxSIi99RNFJ05MHedaJQ=="], + "kubernetes-types": ["kubernetes-types@1.30.0", "", {}, "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q=="], + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], @@ -1633,32 +1617,28 @@ "log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="], - "log-update": ["log-update@8.0.0", "", { "dependencies": { "ansi-escapes": "^7.3.0", "cli-cursor": "^5.0.0", "slice-ansi": "^9.0.0", "string-width": "^8.2.0", "strip-ansi": "^7.2.0", "wrap-ansi": "^10.0.0" } }, "sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg=="], - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="], - "lucide-react": ["lucide-react@1.33.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-MTRwMy0ZlL8Ur/vOAiJ9XGHE+kFPC7brq6MxAm0GiGXEBj0qy0jA/pG4N675oSzciO/UCdX8T+5yUQdmDeTLxg=="], + "lucide-react": ["lucide-react@1.17.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w=="], "maath": ["maath@0.10.8", "", { "peerDependencies": { "@types/three": ">=0.134.0", "three": ">=0.134.0" } }, "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "magicast": ["magicast@0.5.4", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w=="], + "magicast": ["magicast@0.5.3", "", { "dependencies": { "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw=="], "manifold-3d": ["manifold-3d@3.5.1", "", { "dependencies": { "@gltf-transform/core": "^4.2.0", "@gltf-transform/extensions": "^4.2.0", "@gltf-transform/functions": "^4.2.0", "@jridgewell/resolve-uri": "^3.1.2", "@jridgewell/trace-mapping": "^0.3.31", "@jscadui/3mf-export": "^0.5.0", "commander": "^13.1.0", "convert-source-map": "^2.0.0", "fast-xml-parser": "^5.4.2", "fflate": "^0.8.0", "magic-string": "^0.30.21" }, "peerDependencies": { "esbuild-wasm": "^0.27.3" }, "bin": { "manifold-cad": "bin/manifold-cad" } }, "sha512-/+m6kxYMMhnPutcQ5oSmFJiJ+gyP/0fmuUCb9Qeaunvecm/bfqogKYDDJarsnWiFioSMtKheF+lGmSlnYCik9g=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - "media-typer": ["media-typer@1.1.1", "", {}, "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ=="], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="], - "meshline": ["meshline@3.3.1", "", { "peerDependencies": { "three": ">=0.137" } }, "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ=="], "meshoptimizer": ["meshoptimizer@1.1.1", "", {}, "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g=="], @@ -1675,21 +1655,27 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], - "motion": ["motion@12.43.0", "", { "dependencies": { "framer-motion": "^12.43.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-BQgQbSa9Hn3/mtbib0MK53y6JSANa+YKUKlaYnWzAVDH424RYQ5LVpV3pNiWH00BA2z4ojsSdMzqT7g2FQwjuQ=="], + "motion": ["motion@12.40.0", "", { "dependencies": { "framer-motion": "^12.40.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA=="], - "motion-dom": ["motion-dom@12.43.0", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag=="], + "motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="], "motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "nanoid": ["nanoid@5.1.16", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ=="], + "msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], + + "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], + + "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], + + "nanoid": ["nanoid@5.1.11", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -1701,19 +1687,19 @@ "ndarray-pixels": ["ndarray-pixels@5.2.0", "", { "dependencies": { "@types/ndarray": "^1.0.14", "ndarray": "^1.0.19", "ndarray-ops": "^1.2.2", "sharp": "^0.35.0" } }, "sha512-lTh4tFKziAatVTa9crIsidUyn+lqujVOQpzfdBWvdFu2wo9Uo6z261lVX7SgMyP89xGmj3TMTPbbxl9YDnV4SA=="], - "negotiator": ["negotiator@1.1.0", "", { "dependencies": { "content-type": "^2.1.0" } }, "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg=="], + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "next": ["next@16.3.0", "", { "dependencies": { "@next/env": "16.3.0", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.3.0", "@next/swc-darwin-x64": "16.3.0", "@next/swc-linux-arm64-gnu": "16.3.0", "@next/swc-linux-arm64-musl": "16.3.0", "@next/swc-linux-x64-gnu": "16.3.0", "@next/swc-linux-x64-musl": "16.3.0", "@next/swc-win32-arm64-msvc": "16.3.0", "@next/swc-win32-x64-msvc": "16.3.0", "sharp": "^0.35.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A=="], - "node-exports-info": ["node-exports-info@1.6.2", "", { "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", "object.entries": "^1.1.9", "semver": "^6.3.1" } }, "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag=="], + "node-exports-info": ["node-exports-info@1.6.0", "", { "dependencies": { "array.prototype.flatmap": "^1.3.3", "es-errors": "^1.3.0", "object.entries": "^1.1.9", "semver": "^6.3.1" } }, "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw=="], - "node-releases": ["node-releases@2.0.53", "", {}, "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ=="], + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], - "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], + "node-releases": ["node-releases@2.0.47", "", {}, "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og=="], - "number-flow": ["number-flow@0.6.2", "", { "dependencies": { "esm-env": "^1.1.4" } }, "sha512-MCnImG4Q5vPwhSXnov56nOuyyKn6LC+Qd7II1UiKc+ACRtug5iAtn0+CwXNxM38AC5lSowEY+oYEtZX2qMnUyw=="], + "number-flow": ["number-flow@0.6.0", "", { "dependencies": { "esm-env": "^1.1.4" } }, "sha512-K8flNq2Wqus53vjp/btVo3qXFkagF8dIdYavreBfE7hlvFFG/b1HMGEH6nZL+mlrJ+4lbLP9OmPv3t2rmRkpSQ=="], - "nypm": ["nypm@0.6.9", "", { "dependencies": { "citty": "^0.2.2", "pathe": "^2.0.3", "tinyexec": "^1.2.4" }, "bin": { "nypm": "./dist/cli.mjs" } }, "sha512-zxlE2yvSWZWmHcNdT3+5zV2lrCogeE9YOklHrR3dFjqutq5wO7GFDYLFDRXLsYnJzwvy/im9fYoxePvS0VTW0w=="], + "nypm": ["nypm@0.6.6", "", { "dependencies": { "citty": "^0.2.2", "pathe": "^2.0.3", "tinyexec": "^1.1.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -1737,30 +1723,28 @@ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - "ora": ["ora@9.4.1", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.3.2", "string-width": "^8.1.0" } }, "sha512-6VlU9MLXbjVQD04AZCMX28hVtA5bUoadvUqO76MUCVA0ilwJbMiHsITRPfyVm6p/BC0Av/BXMujx39WCe1LEqw=="], + "ora": ["ora@9.4.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.3.2", "string-width": "^8.1.0" } }, "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ=="], - "own-keys": ["own-keys@1.0.2", "", { "dependencies": { "call-bound": "^1.0.4", "get-intrinsic": "^1.3.0", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg=="], + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "oxc-parser": ["oxc-parser@0.143.0", "", { "dependencies": { "@oxc-project/types": "^0.143.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.143.0", "@oxc-parser/binding-android-arm64": "0.143.0", "@oxc-parser/binding-darwin-arm64": "0.143.0", "@oxc-parser/binding-darwin-x64": "0.143.0", "@oxc-parser/binding-freebsd-x64": "0.143.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.143.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.143.0", "@oxc-parser/binding-linux-arm64-gnu": "0.143.0", "@oxc-parser/binding-linux-arm64-musl": "0.143.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.143.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.143.0", "@oxc-parser/binding-linux-riscv64-musl": "0.143.0", "@oxc-parser/binding-linux-s390x-gnu": "0.143.0", "@oxc-parser/binding-linux-x64-gnu": "0.143.0", "@oxc-parser/binding-linux-x64-musl": "0.143.0", "@oxc-parser/binding-openharmony-arm64": "0.143.0", "@oxc-parser/binding-win32-arm64-msvc": "0.143.0", "@oxc-parser/binding-win32-ia32-msvc": "0.143.0", "@oxc-parser/binding-win32-x64-msvc": "0.143.0" } }, "sha512-ov0NzaDCOInknS7mP1cwKdJERt3utPW8ldjtdUXQ8Ty0GEFD08wk422vCUN0d7pST6kqtV7dxoI9w1Zi0l/9TA=="], + "oxc-parser": ["oxc-parser@0.132.0", "", { "dependencies": { "@oxc-project/types": "^0.132.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.132.0", "@oxc-parser/binding-android-arm64": "0.132.0", "@oxc-parser/binding-darwin-arm64": "0.132.0", "@oxc-parser/binding-darwin-x64": "0.132.0", "@oxc-parser/binding-freebsd-x64": "0.132.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.132.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.132.0", "@oxc-parser/binding-linux-arm64-gnu": "0.132.0", "@oxc-parser/binding-linux-arm64-musl": "0.132.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.132.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.132.0", "@oxc-parser/binding-linux-riscv64-musl": "0.132.0", "@oxc-parser/binding-linux-s390x-gnu": "0.132.0", "@oxc-parser/binding-linux-x64-gnu": "0.132.0", "@oxc-parser/binding-linux-x64-musl": "0.132.0", "@oxc-parser/binding-openharmony-arm64": "0.132.0", "@oxc-parser/binding-wasm32-wasi": "0.132.0", "@oxc-parser/binding-win32-arm64-msvc": "0.132.0", "@oxc-parser/binding-win32-ia32-msvc": "0.132.0", "@oxc-parser/binding-win32-x64-msvc": "0.132.0" } }, "sha512-+0LAPHaqtfQlvWdpaAa09SmOaZZgP8C552xosEkGJ4+ruEwP1Vgx+sqBgcBCNfR6KDCmagGOZTde8wmAvcI/Hg=="], - "oxc-resolver": ["oxc-resolver@11.24.2", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.24.2", "@oxc-resolver/binding-android-arm64": "11.24.2", "@oxc-resolver/binding-darwin-arm64": "11.24.2", "@oxc-resolver/binding-darwin-x64": "11.24.2", "@oxc-resolver/binding-freebsd-x64": "11.24.2", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", "@oxc-resolver/binding-linux-x64-musl": "11.24.2", "@oxc-resolver/binding-openharmony-arm64": "11.24.2", "@oxc-resolver/binding-wasm32-wasi": "11.24.2", "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" } }, "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw=="], + "oxc-resolver": ["oxc-resolver@11.20.0", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.20.0", "@oxc-resolver/binding-android-arm64": "11.20.0", "@oxc-resolver/binding-darwin-arm64": "11.20.0", "@oxc-resolver/binding-darwin-x64": "11.20.0", "@oxc-resolver/binding-freebsd-x64": "11.20.0", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.20.0", "@oxc-resolver/binding-linux-arm-musleabihf": "11.20.0", "@oxc-resolver/binding-linux-arm64-gnu": "11.20.0", "@oxc-resolver/binding-linux-arm64-musl": "11.20.0", "@oxc-resolver/binding-linux-ppc64-gnu": "11.20.0", "@oxc-resolver/binding-linux-riscv64-gnu": "11.20.0", "@oxc-resolver/binding-linux-riscv64-musl": "11.20.0", "@oxc-resolver/binding-linux-s390x-gnu": "11.20.0", "@oxc-resolver/binding-linux-x64-gnu": "11.20.0", "@oxc-resolver/binding-linux-x64-musl": "11.20.0", "@oxc-resolver/binding-openharmony-arm64": "11.20.0", "@oxc-resolver/binding-wasm32-wasi": "11.20.0", "@oxc-resolver/binding-win32-arm64-msvc": "11.20.0", "@oxc-resolver/binding-win32-x64-msvc": "11.20.0" } }, "sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g=="], - "oxlint": ["oxlint@1.77.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.77.0", "@oxlint/binding-android-arm64": "1.77.0", "@oxlint/binding-darwin-arm64": "1.77.0", "@oxlint/binding-darwin-x64": "1.77.0", "@oxlint/binding-freebsd-x64": "1.77.0", "@oxlint/binding-linux-arm-gnueabihf": "1.77.0", "@oxlint/binding-linux-arm-musleabihf": "1.77.0", "@oxlint/binding-linux-arm64-gnu": "1.77.0", "@oxlint/binding-linux-arm64-musl": "1.77.0", "@oxlint/binding-linux-ppc64-gnu": "1.77.0", "@oxlint/binding-linux-riscv64-gnu": "1.77.0", "@oxlint/binding-linux-riscv64-musl": "1.77.0", "@oxlint/binding-linux-s390x-gnu": "1.77.0", "@oxlint/binding-linux-x64-gnu": "1.77.0", "@oxlint/binding-linux-x64-musl": "1.77.0", "@oxlint/binding-openharmony-arm64": "1.77.0", "@oxlint/binding-win32-arm64-msvc": "1.77.0", "@oxlint/binding-win32-ia32-msvc": "1.77.0", "@oxlint/binding-win32-x64-msvc": "1.77.0" }, "peerDependencies": { "oxlint-tsgolint": ">=7.0.2001", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg=="], + "oxlint": ["oxlint@1.69.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.69.0", "@oxlint/binding-android-arm64": "1.69.0", "@oxlint/binding-darwin-arm64": "1.69.0", "@oxlint/binding-darwin-x64": "1.69.0", "@oxlint/binding-freebsd-x64": "1.69.0", "@oxlint/binding-linux-arm-gnueabihf": "1.69.0", "@oxlint/binding-linux-arm-musleabihf": "1.69.0", "@oxlint/binding-linux-arm64-gnu": "1.69.0", "@oxlint/binding-linux-arm64-musl": "1.69.0", "@oxlint/binding-linux-ppc64-gnu": "1.69.0", "@oxlint/binding-linux-riscv64-gnu": "1.69.0", "@oxlint/binding-linux-riscv64-musl": "1.69.0", "@oxlint/binding-linux-s390x-gnu": "1.69.0", "@oxlint/binding-linux-x64-gnu": "1.69.0", "@oxlint/binding-linux-x64-musl": "1.69.0", "@oxlint/binding-openharmony-arm64": "1.69.0", "@oxlint/binding-win32-arm64-msvc": "1.69.0", "@oxlint/binding-win32-ia32-msvc": "1.69.0", "@oxlint/binding-win32-x64-msvc": "1.69.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw=="], - "oxlint-plugin-react-doctor": ["oxlint-plugin-react-doctor@0.9.12", "", { "dependencies": { "@shaderfrog/glsl-parser": "^7.0.1", "@typescript-eslint/types": "^8.59.3", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "lightningcss": "^1.33.0", "oxc-parser": "^0.143.0" } }, "sha512-BplcCUU/tGByFGgY1YIax6evUmjk0K8zOGGrdPs3A3dqamrzjUvVuJdYpM1Ftyt/B5fFx6+VwRrWi3YZbIz4VQ=="], + "oxlint-plugin-react-doctor": ["oxlint-plugin-react-doctor@0.5.0", "", { "dependencies": { "@typescript-eslint/types": "^8.59.3", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "oxc-parser": "^0.132.0" } }, "sha512-2oXQZKc3N2XPGmKQ0+GtZ4TSlNb4Jm1DKDrxhBE1zBK01PIjz9lXSUQm0hFCXFmlGmjVF7/GE11U9p2Oe0o9Nw=="], "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], "pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -1771,6 +1755,8 @@ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -1779,26 +1765,22 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], - "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "png-js": ["png-js@1.1.0", "", { "dependencies": { "browserify-zlib": "^0.2.0" } }, "sha512-PM/uYGzGdNSzqeOgly68+6wKQDL1SY0a/N+OEa/+br6LnHWOAJB0Npiamnodfq3jd2LS/i2fMeOKSAILjA+m5Q=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], + "postcss": ["postcss@8.5.23", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg=="], "potpack": ["potpack@1.0.2", "", {}, "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ=="], - "preact": ["preact@10.29.8", "", { "peerDependencies": { "preact-render-to-string": ">=5" }, "optionalPeers": ["preact-render-to-string"] }, "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q=="], + "preact": ["preact@10.29.2", "", {}, "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], - "promise-worker-transferable": ["promise-worker-transferable@1.0.4", "", { "dependencies": { "is-promise": "^2.1.0", "lie": "^3.0.2" } }, "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw=="], "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], @@ -1811,19 +1793,21 @@ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "qs": ["qs@6.15.3", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A=="], + "pure-rand": ["pure-rand@8.4.0", "", {}, "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A=="], + + "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "range-parser": ["range-parser@1.3.0", "", {}, "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], - "react": ["react@19.2.8", "", {}, "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw=="], + "react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="], - "react-doctor": ["react-doctor@0.9.12", "", { "dependencies": { "@astrojs/compiler": "^4.0.0", "@sentry/node": "^10.54.0", "agent-install": "0.0.5", "conf": "^15.1.0", "confbox": "^0.2.4", "deslop-js": "0.9.12", "eslint-plugin-react-hooks": "^7.1.1", "jiti": "^2.7.0", "magicast": "^0.5.3", "oxc-resolver": "^11.24.2", "oxlint": ">=1.77.0 <1.78.0", "oxlint-plugin-react-doctor": "0.9.12", "prompts": "^2.4.2", "typescript": ">=5.0.4 <6", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.12", "vscode-uri": "^3.1.0", "yaml": "^2.9.0", "yoga-layout": "~3.2.1" }, "bin": { "react-doctor": "bin/react-doctor.js" } }, "sha512-H7RNg13RYKwpQvi3+O3IkSj8pAD1pGTxSetxu7aOwXX3wmF+BydCLDiWxkPT9Pq7bIMHjuJ0taSZLsxEjlNjcA=="], + "react-doctor": ["react-doctor@0.5.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@effect/platform-node-shared": "4.0.0-beta.70", "@sentry/node": "^10.54.0", "agent-install": "0.0.5", "conf": "^15.1.0", "confbox": "^0.2.4", "deslop-js": "^0.0.21", "effect": "4.0.0-beta.70", "eslint-plugin-react-hooks": "^7.1.1", "jiti": "^2.7.0", "magicast": "^0.5.3", "oxlint": "^1.66.0", "oxlint-plugin-react-doctor": "0.5.0", "prompts": "^2.4.2", "typescript": ">=5.0.4 <7", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.12", "vscode-uri": "^3.1.0" }, "bin": { "react-doctor": "bin/react-doctor.js" } }, "sha512-MEx7RgRv2kXp6HoPMzc7fFz5Mm3vCqS3Z7clkjmDbsPamjCz7TrDDWQarfaPr7woWA6FOAaWHt1bGhQ88cfEEw=="], - "react-dom": ["react-dom@19.2.8", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.8" } }, "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ=="], + "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="], "react-grab": ["react-grab@0.1.50", "", { "dependencies": { "@react-grab/cli": "0.1.50", "bippy": "^0.6.1" }, "peerDependencies": { "react": ">=17.0.0" }, "optionalPeers": ["react"], "bin": { "react-grab": "bin/cli.js" } }, "sha512-zRkHKq/8a1msCpEOp8BDROeQZT50m0OH2XPrP6jk5op+JAHrlsm3pj7eAQMOsct87EZDeGNnu4r+sGsJJzyw1Q=="], @@ -1851,8 +1835,6 @@ "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="], - "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], "restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="], @@ -1873,8 +1855,6 @@ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "semifies": ["semifies@1.0.0", "", {}, "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw=="], - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], @@ -1907,10 +1887,6 @@ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], - "slice-ansi": ["slice-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "is-fullwidth-code-point": "^5.1.0" } }, "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA=="], - - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "stats-gl": ["stats-gl@2.4.2", "", { "dependencies": { "@types/three": "*", "three": "^0.170.0" } }, "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ=="], @@ -1923,7 +1899,7 @@ "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], - "string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="], "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], @@ -1937,8 +1913,6 @@ "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], "strnum": ["strnum@2.4.2", "", { "dependencies": { "anynum": "^1.0.1" } }, "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw=="], @@ -1959,7 +1933,7 @@ "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], - "tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="], + "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], @@ -1967,13 +1941,13 @@ "three-bvh-csg": ["three-bvh-csg@0.0.18", "", { "peerDependencies": { "three": ">=0.179.0", "three-mesh-bvh": ">=0.9.7" } }, "sha512-M3GCZMmGFgASGuDf+YMamM83nVlD/vdwzVHcYbFxgW+g1S7/nKPiuY00YVHOMbjmJPh8mLevGZL65ItHUuGt2w=="], - "three-mesh-bvh": ["three-mesh-bvh@0.9.14", "", { "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-xJzfUXnLYjgw5tRKGxjfJW3Pcx0IbwNskvpdwRryhK07SYrKrYB4W8zAaPxu784gK7G4lCBgG+vfG3YeYn95kg=="], + "three-mesh-bvh": ["three-mesh-bvh@0.9.10", "", { "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-UOlTgPIeqUURcwaG8knxvBaruwZlC4X3/WSHEFO7rYvMVv/YNUrkfFEszvfj36pXV88dCHoHNnIp0PifkirnTQ=="], "three-stdlib": ["three-stdlib@2.36.1", "", { "dependencies": { "@types/draco3d": "^1.4.0", "@types/offscreencanvas": "^2019.6.4", "@types/webxr": "^0.5.2", "draco3d": "^1.4.1", "fflate": "^0.6.9", "potpack": "^1.0.1" }, "peerDependencies": { "three": ">=0.128.0" } }, "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg=="], "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], - "tinyexec": ["tinyexec@1.3.0", "", {}, "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ=="], + "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], @@ -1981,9 +1955,11 @@ "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "troika-three-text": ["troika-three-text@0.52.5", "", { "dependencies": { "bidi-js": "^1.0.2", "troika-three-utils": "^0.52.5", "troika-worker-utils": "^0.52.0", "webgl-sdf-generator": "1.1.1" }, "peerDependencies": { "three": ">=0.125.0" } }, "sha512-Ry3jRhic9pzcY4JduSvRRyDmVOSqEW19gT4vtK+aCiPNVcDlmkxvGG0YbFd36RTDq1wExOupXnvNF/j1oiHHDA=="], + "toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="], + + "troika-three-text": ["troika-three-text@0.52.4", "", { "dependencies": { "bidi-js": "^1.0.2", "troika-three-utils": "^0.52.4", "troika-worker-utils": "^0.52.0", "webgl-sdf-generator": "1.1.1" }, "peerDependencies": { "three": ">=0.125.0" } }, "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg=="], - "troika-three-utils": ["troika-three-utils@0.52.5", "", { "peerDependencies": { "three": ">=0.125.0" } }, "sha512-WsePbcX8RtfidRfsxK1eCZCjF81ZDzAKHH/evLs0hdV2wpoCb0vArGZHdzdOJrSS3k4zfdtbKDaBh8+phkrYnw=="], + "troika-three-utils": ["troika-three-utils@0.52.4", "", { "peerDependencies": { "three": ">=0.125.0" } }, "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A=="], "troika-worker-utils": ["troika-worker-utils@0.52.0", "", {}, "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw=="], @@ -1993,13 +1969,13 @@ "tunnel-rat": ["tunnel-rat@0.1.2", "", { "dependencies": { "zustand": "^4.3.2" } }, "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ=="], - "turbo": ["turbo@2.10.11", "", { "optionalDependencies": { "@turbo/darwin-64": "2.10.11", "@turbo/darwin-arm64": "2.10.11", "@turbo/linux-64": "2.10.11", "@turbo/linux-arm64": "2.10.11", "@turbo/windows-64": "2.10.11", "@turbo/windows-arm64": "2.10.11" }, "bin": { "turbo": "bin/turbo" } }, "sha512-yQfwQVoRXwOuyX1LxiJFBFNg6VfuYh+/RyZLd82+isgyLkBXw3S5XRRzvcck1FAjSCG5sVyLd+O1eDMvYa3J7g=="], + "turbo": ["turbo@2.9.17", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.17", "@turbo/darwin-arm64": "2.9.17", "@turbo/linux-64": "2.9.17", "@turbo/linux-arm64": "2.9.17", "@turbo/windows-64": "2.9.17", "@turbo/windows-arm64": "2.9.17" }, "bin": { "turbo": "bin/turbo" } }, "sha512-91Q3KxfHJn7esFu2Ic6j9pkvQqWjncQCOp7r1gCKChRSb/+T/yIjsavAmbGLmFRKAzSjmWW/FMrcknmJ4hEOPA=="], "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "type-fest": ["type-fest@5.8.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA=="], + "type-fest": ["type-fest@5.7.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg=="], "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], @@ -2013,13 +1989,11 @@ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], - "typescript-eslint": ["typescript-eslint@8.67.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.67.0", "@typescript-eslint/parser": "8.67.0", "@typescript-eslint/typescript-estree": "8.67.0", "@typescript-eslint/utils": "8.67.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg=="], - - "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], + "typescript-eslint": ["typescript-eslint@8.61.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.61.0", "@typescript-eslint/parser": "8.61.0", "@typescript-eslint/typescript-estree": "8.61.0", "@typescript-eslint/utils": "8.61.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], - "ultracite": ["ultracite@7.10.6", "", { "dependencies": { "@clack/prompts": "^1.5.1", "cli-truncate": "^6.1.1", "commander": "^15.0.0", "deepmerge": "^4.3.1", "empathic": "^2.0.1", "execa": "^10.0.1", "fast-glob": "^3.3.3", "find-workspaces": "^0.3.1", "jsonc-parser": "^3.3.1", "log-update": "^8.0.0", "magicast": "^0.5.4", "nypm": "^0.6.6", "resolve.exports": "^2.0.3", "string-width": "^8.2.2", "yaml": "^2.9.0", "zod": "^4.4.3" }, "peerDependencies": { "oxfmt": ">=0.1.0", "oxlint": "^1.79.0" }, "optionalPeers": ["oxfmt", "oxlint"], "bin": { "ultracite": "dist/index.js" } }, "sha512-kRoCy4z1A/rk0upPdIAJhOo4ocsUx9uTPsPcq3Z+xP1Bxg6dcKkwqX4siYJ1ba4z4kRbyxaEO4Zi5bw/iXZrFA=="], + "ultracite": ["ultracite@7.8.2", "", { "dependencies": { "@clack/prompts": "^1.5.1", "commander": "^15.0.0", "cross-spawn": "^7.0.6", "deepmerge": "^4.3.1", "glob": "^13.0.6", "jsonc-parser": "^3.3.1", "nypm": "^0.6.6", "yaml": "^2.9.0", "zod": "^4.4.3" }, "peerDependencies": { "oxfmt": ">=0.1.0", "oxlint": "^1.0.0" }, "optionalPeers": ["oxfmt", "oxlint"], "bin": { "ultracite": "dist/index.js" } }, "sha512-+XeWzAEsewEr/kM686bOIWWt5DN+Pww4JUEOQUqOx4p/Pi58FWV+vPtEo2wi5WVWSgIkf8NzfTWGXmJjdqMl8g=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], @@ -2029,15 +2003,13 @@ "unicode-trie": ["unicode-trie@2.0.0", "", { "dependencies": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" } }, "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ=="], - "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], - "uniq": ["uniq@1.0.1", "", {}, "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "unplugin": ["unplugin@3.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.4", "webpack-virtual-modules": "^0.6.2" }, "peerDependencies": { "@farmfe/core": "*", "@rspack/core": "*", "bun-types-no-globals": "*", "esbuild": "*", "rolldown": "*", "rollup": "*", "unloader": "*", "vite": "*", "webpack": "*" }, "optionalPeers": ["@farmfe/core", "@rspack/core", "bun-types-no-globals", "esbuild", "rolldown", "rollup", "unloader", "vite", "webpack"] }, "sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg=="], + "unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="], - "update-browserslist-db": ["update-browserslist-db@1.3.1", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ=="], + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -2049,6 +2021,8 @@ "utility-types": ["utility-types@3.11.0", "", {}, "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw=="], + "uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], @@ -2081,16 +2055,14 @@ "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - "which-command": ["which-command@0.1.0", "", { "bin": { "which-command": "cli.js" } }, "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA=="], - "which-typed-array": ["which-typed-array@1.1.22", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw=="], "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "wrap-ansi": ["wrap-ansi@10.0.1", "", { "dependencies": { "ansi-styles": "^6.2.3", "string-width": "^8.2.0" } }, "sha512-M0N4xzyzosiIok3svYlEo1sdLZts/8FPgYH/GPC3wvlmPoRvnoManGMrE54waYj3tISA8w6lsdesfVv67qSr8Q=="], - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + "xml-naming": ["xml-naming@0.3.0", "", {}, "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -2099,9 +2071,7 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "yoctocolors": ["yoctocolors@2.2.0", "", {}, "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg=="], - - "yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], @@ -2111,7 +2081,9 @@ "zundo": ["zundo@2.3.0", "", { "peerDependencies": { "zustand": "^4.3.0 || ^5.0.0" } }, "sha512-4GXYxXA17SIKYhVbWHdSEU04P697IMyVGXrC2TnzoyohEAWytFNOKqOp5gTGvaW93F/PM5Y0evbGtOPF0PWQwQ=="], - "zustand": ["zustand@5.0.15", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-MpSEjRiBkA9crSYeOUH32rJC7SVqAbm0Fqcqge/bUi2PPoLcBWKOsG+C8mevmpr8TwXHBVkChbbJiyvkE+i/3A=="], + "zustand": ["zustand@5.0.14", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g=="], + + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], @@ -2119,55 +2091,47 @@ "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - "@next/eslint-plugin-next/fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], + "@oxc-parser/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], - "@oxc-resolver/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="], + "@oxc-resolver/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], "@react-grab/cli/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], - "@react-grab/cli/ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="], + "@react-grab/cli/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@react-three/drei/three-mesh-bvh": ["three-mesh-bvh@0.8.3", "", { "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg=="], - "@tailwindcss/oxide/@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw=="], - - "@tailwindcss/oxide/@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q=="], - "@tailwindcss/oxide/@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg=="], - "@tailwindcss/oxide/@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g=="], - - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" }, "bundled": true }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="], - - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.6", "", {}, "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw=="], + "@tailwindcss/postcss/postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "@typescript-eslint/typescript-estree/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@typescript-eslint/typescript-estree/semver": ["semver@7.8.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg=="], "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], "agent-install/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], - "body-parser/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], - "browserify-zlib/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - "conf/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "conf/semver": ["semver@7.8.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg=="], - "deslop-js/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + "deslop-js/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - "deslop-js/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "deslop-js/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], @@ -2179,6 +2143,8 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "ifc-converter-app/typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], "linebreak/base64-js": ["base64-js@0.0.8", "", {}, "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw=="], @@ -2187,31 +2153,19 @@ "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "negotiator/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], - - "next/postcss": ["postcss@8.5.23", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg=="], - - "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], - "ora/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "oxlint-plugin-react-doctor/eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="], "oxlint-plugin-react-doctor/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], - "oxlint-plugin-react-doctor/lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="], - - "pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], - - "postcss/nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], + "postcss/nanoid": ["nanoid@3.3.17", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g=="], "react-doctor/agent-install": ["agent-install@0.0.5", "", { "dependencies": { "@iarna/toml": "^2.2.5", "commander": "^14.0.0", "jsonc-parser": "^3.3.1", "picocolors": "^1.1.1", "prompts": "^2.4.2", "yaml": "^2.8.3" }, "bin": { "agent-install": "bin/agent-install.mjs" } }, "sha512-nHlms9BkP8ZiY79HrwCGiA2DcNaXrAaJrCM/BEqQ7MEsSKyCk+2A76xPGylIfASZSZE0SaU3T0bNSg4rBPIJAQ=="], "react-doctor/eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.1.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "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" } }, "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g=="], - "react-doctor/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - - "react-scan/bippy": ["bippy@0.5.43", "", { "peerDependencies": { "react": ">=17.0.1" } }, "sha512-Tvu7b1M7+d8b9/YHaCeODEsi2CgbuoBql+dWSBrNnCuqJ1gMUeY3i0r+319hvjjl5GVBP6FFWxrKnq3fhZER0w=="], + "react-scan/bippy": ["bippy@0.5.41", "", { "peerDependencies": { "react": ">=17.0.1" } }, "sha512-jCP2pXXLhXqPrAN+iSEFZmLI4uUM4fjSqajh0K+TmM062VehfDT3ZJNkrTGyN701Z5XMejs9qAudSqkMGhSMKg=="], "react-scan/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], @@ -2219,54 +2173,32 @@ "sharp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - - "three-stdlib/fflate": ["fflate@0.6.11", "", {}, "sha512-3JyEFWGjFn7zHmoa9+zG1BmW7X2okcmAB+0Cnu9UFbVs/jCBnl2A8o065ZlXiw145K3eBM3uLuzrYXC0RK7eDg=="], + "three-stdlib/fflate": ["fflate@0.6.10", "", {}, "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg=="], "tunnel-rat/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], - "type-is/content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], - - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "@next/eslint-plugin-next/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], - - "deslop-js/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], + "@tailwindcss/postcss/postcss/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], - "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "next/postcss/nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.33.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.33.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg=="], + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], - "oxlint-plugin-react-doctor/lightningcss/lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.33.0", "", { "os": "linux", "cpu": "arm" }, "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ=="], + "deslop-js/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "oxlint-plugin-react-doctor/lightningcss/lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg=="], + "deslop-js/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], - "oxlint-plugin-react-doctor/lightningcss/lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw=="], - - "oxlint-plugin-react-doctor/lightningcss/lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.33.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA=="], + "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "oxlint-plugin-react-doctor/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA=="], + "glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], "react-doctor/agent-install/commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "deslop-js/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], } }