regressing rn

This commit is contained in:
legop3
2026-04-29 18:31:02 -04:00
parent fed0cab0b8
commit 01a8d044e7
61 changed files with 139 additions and 17 deletions
+22 -8
View File
@@ -35,22 +35,22 @@
## Current phase
- [x] Phase 1: Inventory + usage mapping (server + webui)
- [x] Phase 2: Refactor highest-impact offenders first
- [ ] Phase 3: Sweep remaining services/components
- [x] Phase 3: Sweep remaining services/components
- [ ] Phase 4: Dead code/file removal pass
- [ ] Phase 5: Final regression validation
- [ ] Phase 5: Final regression validation (in progress)
## Server backend
### BIGGEST OFFENDERS
- [ ] audio forward service
- [ ] button box service
- [x] audio forward service
- [x] button box service
- [x] chat service
- [x] discord bot service
- [x] home assistant service
- [ ] llm commentary service
- [x] llm commentary service
- [x] private rover access request service
- [x] replay services (consolidated under replayEngineV2)
- [x] room camera services (consolidated into roomCameraService multipart folder)
- [ ] rover manager service (in progress: constants/state extracted)
- [x] rover manager service
- [x] session service
- [x] turn service
- [x] verification service
@@ -119,8 +119,8 @@
- top down map
### LARGE CHANGES
- Split `webui/src/mini/MiniSummaryApp.jsx` into folderized modules under `webui/src/mini/MiniSummaryApp/` with a compatibility entrypoint preserved.
- Split `webui/src/spectate/SpectatorApp.jsx` into folderized modules under `webui/src/spectate/SpectatorApp/` with a compatibility entrypoint preserved.
- Split mini summary app into folderized modules under `webui/src/mini/MiniSummaryApp/`, then removed the now-unneeded external wrapper (`webui/src/mini/MiniSummaryApp.jsx`) and rewired app bootstrap imports directly to the folder entrypoint module.
- Split spectator app into folderized modules under `webui/src/spectate/SpectatorApp/`, then removed the now-unneeded external wrapper (`webui/src/spectate/SpectatorApp.jsx`) and rewired app bootstrap imports directly to the folder entrypoint module.
- Split `webui/src/components/VideoTile.jsx` by extracting HUD, overlays, chat input, and constants into `webui/src/components/VideoTile/` while preserving the existing `VideoTile.jsx` public component API.
- Split `webui/src/components/vip/VipAudioUploadCard.jsx` by extracting transport/audio helpers and UI atoms into `webui/src/components/vip/VipAudioUploadCard/` while preserving the existing `VipAudioUploadCard.jsx` import/export API.
- Split `webui/src/components/AdminPanel.jsx` into `webui/src/components/AdminPanel/` and extracted monitor/health/log/LLM helper modules; updated consumers to folder entrypoint and removed external wrapper file.
@@ -137,3 +137,17 @@
- [ ] Imports/exports updated with no external behavior change.
- [ ] Verified references/usages still resolve.
- [ ] Passed targeted checks/tests for touched area.
## Phase 4 notes
- Removed stale WebUI compatibility wrapper files `webui/src/mini/MiniSummaryApp.jsx` and `webui/src/spectate/SpectatorApp.jsx` after reference verification; rewired `webui/src/main.jsx` directly to folder entrypoint modules.
- Verified no remaining replay/room-camera/rover-snapshot legacy service imports (`replayBuildService`, `replayService`, `replaySourceService`, `replaySocketService`, `roomCameraReplayService`, `roomCameraSocketService`, `roomCameraSnapshotService`, `roverSnapshotSocketService`) in server startup/runtime wiring.
## Phase 5 checklist
- [x] WebUI production build passes (`npm run build`), including updated import graph after wrapper removals.
- [x] Server JS syntax check passes (`node --check` across `server/src/**/*.js`).
- [ ] Live rover snapshots: verify continuously updating snapshots from mediaMTX writer on deployed server.
- [ ] Replay from WebUI button: verify request -> build -> delivery path on deployed server.
- [ ] Replay from Discord command: verify request -> build -> delivery path on deployed server.
- [ ] Discord verification + private access request flow: verify end-to-end behavior on deployed server.
- [ ] Home Assistant idle-light behavior: verify expected mode/idle transitions on deployed server.
- [ ] Driver/session/turn core flow: verify control assignment, queue movement, command acceptance/rejection behavior.
+1 -1
View File
@@ -19,7 +19,7 @@ mkdir -p "$SNAP_DIR"
exec ffmpeg -hide_banner -loglevel warning -nostdin -y \
-i "srt://127.0.0.1:9000?streamid=read:${PATH_NAME}" \
-an \
-vf fps=2 \
-vf fps=1 \
-q:v 6 \
-update 1 \
"${SNAP_DIR}/${PATH_NAME}.jpg"
+2
View File
@@ -1,3 +1,5 @@
// Global Config
// Purpose: Stores process-level mutable configuration shared across services. Scope: Provides read/write access to runtime config loaded at server startup.
const path = require('path');
module.exports = {
+2
View File
@@ -1,3 +1,5 @@
// Global HTTP Server
// Purpose: Stores the process-level HTTP server instance created at bootstrap. Scope: Enables services to access server lifecycle state without circular imports.
const http = require('http');
const express = require('express');
const morgan = require('morgan');
+2
View File
@@ -1,3 +1,5 @@
// Global Socket.IO
// Purpose: Stores the singleton Socket.IO server instance for cross-service access. Scope: Exposes getters/setters used during startup wiring and runtime event emission.
const { Server: SocketIOServer } = require('socket.io');
const { httpServer } = require('./http');
+2
View File
@@ -1,3 +1,5 @@
// Global Logger
// Purpose: Configures structured console logging helpers used by server services. Scope: Formats timestamped log lines and supports child logger prefixes.
const sinks = new Set();
function notifySinks(level, label, args) {
+2
View File
@@ -1,3 +1,5 @@
// Global WebSocket Server
// Purpose: Stores the shared raw WebSocket server instance for modules that need direct access. Scope: Centralizes setter/getter access for process-wide WS wiring.
const { WebSocketServer } = require('ws');
const { httpServer } = require('./http');
const logger = require('./logger');
+2
View File
@@ -1,3 +1,5 @@
// Config Loader Helper
// Purpose: Loads and validates YAML server configuration from configured paths. Scope: Provides normalized config access with sane defaults and cache behavior.
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
+2
View File
@@ -1,3 +1,5 @@
// IP Resolver Helper
// Purpose: Resolves client IP addresses from request/socket metadata and proxy headers. Scope: Normalizes IP extraction so auth/logging services use consistent address values.
const net = require('net');
function extractForwardedIp(value) {
+2
View File
@@ -1,3 +1,5 @@
// Sensor Decoder Helper
// Purpose: Decodes incoming rover sensor payloads into normalized telemetry fields. Scope: Handles binary/string parsing and defensive fallback behavior for malformed frames.
const HEADER = 0x13;
const CHARGING_STATE = {
0: 'not charging',
@@ -1,3 +1,5 @@
// Reward Definition: Assignment Roulette
// Purpose: Defines the assignment-roulette reward for reshuffling control assignments. Scope: Encodes reward identity, messaging, and runtime action parameters.
module.exports = {
id: 'assignmentRoulette',
name: 'Rover Reassignment',
@@ -1,3 +1,5 @@
// Reward Definition: Camera Whiplash
// Purpose: Defines the camera-whiplash deterrence reward and timing/strength settings. Scope: Supplies reusable reward metadata and execution parameters for chaos triggers.
const STEP_MS = 220;
const DURATION_MS = 30 * 1000;
const STEPS = Math.ceil(DURATION_MS / STEP_MS);
@@ -1,3 +1,5 @@
// Reward Definition: Chat Spam
// Purpose: Defines the chat-spam reward for automated disruptive message bursts. Scope: Exposes metadata and effect settings consumed by reward execution.
const LETTERS = 'abcdefghijklmnopqrstuvwxyz';
const BURST_COUNT = 18;
const MIN_BURST_SIZE = 2;
@@ -1,3 +1,5 @@
// Reward Definition: Darkness
// Purpose: Defines the darkness reward that alters visibility/lighting behavior. Scope: Encapsulates reward metadata and effect configuration for runtime execution.
const DURATION_MS = 15 * 60 * 1000;
const LIGHT_ENFORCE_TICK_MS = 3000;
// Rover daemon semantics are inverted:
@@ -1,3 +1,5 @@
// Reward Definition: Discord Stalker Ping
// Purpose: Defines the Discord ping reward that notifies configured channels/users. Scope: Provides reward metadata and dispatch parameters for integration handlers.
module.exports = {
id: 'discordStalkerPing',
name: 'Discord Ping',
@@ -1,3 +1,5 @@
// Reward Definition: Dock Panic
// Purpose: Defines the dock-panic deterrence reward behavior and metadata. Scope: Produces a deterministic action payload used by reward execution pipelines.
const DOCK_COMMAND_BASE64 = Buffer.from([143]).toString('base64');
module.exports = {
@@ -1,3 +1,5 @@
// Reward Definition: Ghost Typing Spam
// Purpose: Defines the ghost-typing spam reward used for chat-based deterrence events. Scope: Exposes reward metadata and handler inputs for moderation/reward pipelines.
const NAMES = ['ross', 'david', 'chirpet', 'caydu', 'meow', 'wawa'];
const BURSTS = 120;
const MIN_BURST_DELAY_MS = 70;
@@ -1,3 +1,5 @@
// Reward Definition: Light Strobe
// Purpose: Defines the light-strobe deterrence reward and activation contract. Scope: Encapsulates reward identity, labels, and effect parameters for runtime dispatch.
const STROBE_MS = 30 * 1000;
const TICK_MS = 70;
@@ -1,3 +1,5 @@
// Reward Definition: Mode Jam
// Purpose: Defines the mode-jam reward that interferes with mode/state transitions. Scope: Supplies effect metadata and execution inputs to reward orchestration code.
const MIN_DURATION_MS = 5 * 60 * 1000;
const MAX_DURATION_MS = 10 * 60 * 1000;
+2
View File
@@ -1,3 +1,5 @@
// Reward Registry
// Purpose: Registers and exports all deterrence/chaos reward definitions. Scope: Builds the canonical reward catalog consumed by button box and moderation flows.
const dockPanic = require('./definitions/dockPanic');
const cameraWhiplash = require('./definitions/cameraWhiplash');
const lightStrobe = require('./definitions/lightStrobe');
+2
View File
@@ -1,3 +1,5 @@
// Main Application Shell
// Purpose: Composes the primary rover control interface and page-level layout. Scope: Orchestrates high-level panels, overlays, and feature modules for the default route.
import { useCallback, useEffect, useMemo, useState } from 'react';
import TelemetryPanel from './components/TelemetryPanel/index.jsx';
import ReplaySourcesPanel from './components/ReplaySourcesPanel/index.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Chat Context Provider
// Purpose: Maintains global chat message state, posting helpers, and typing indicators. Scope: Provides chat event subscriptions and mutation actions for chat-capable components.
/* eslint-disable react-refresh/only-export-components */
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
+2
View File
@@ -1,3 +1,5 @@
// Session Context Provider
// Purpose: Tracks user session identity, roles, queue state, and control assignment data. Scope: Supplies synchronized session state and update hooks to the UI tree.
/* eslint-disable react-refresh/only-export-components */
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
+2
View File
@@ -1,3 +1,5 @@
// Socket Context Provider
// Purpose: Creates React context for shared socket lifecycle and connection state. Scope: Owns socket initialization, reconnect behavior, and consumer hooks.
/* eslint-disable react-refresh/only-export-components */
// src/context/SocketContext.jsx
+2
View File
@@ -1,3 +1,5 @@
// Telemetry Context Provider
// Purpose: Maintains shared telemetry snapshots and rover status streams for UI consumers. Scope: Subscribes to telemetry events and exposes normalized read APIs to components.
/* eslint-disable react-refresh/only-export-components */
import { createContext, useContext, useMemo, useState, useEffect } from 'react';
+2
View File
@@ -1,3 +1,5 @@
// Control Context Provider
// Purpose: Exposes control-system state/actions to control-capable components. Scope: Owns reducer wiring, pipeline integration, and top-level provider hooks.
import { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef } from 'react';
import { controlReducer, initialControlState } from './controlReducer.js';
import { computeDifferentialSpeeds, clamp } from './controlMath.js';
+2
View File
@@ -1,3 +1,5 @@
// Control Command Pipeline
// Purpose: Converts normalized inputs into command packets sent to the server. Scope: Applies throttling/coalescing/safety filters before socket command emission.
import { useCallback, useMemo } from 'react';
import { useSocket } from '../context/SocketContext.jsx';
import { useSessionSelector } from '../context/SessionContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Control System Constants
// Purpose: Defines immutable control tuning and command constants for input pipelines. Scope: Central source of truth for movement scaling, deadzones, and timing values.
export const AUX_LIMITS = {
main: [-127, 127],
side: [-127, 127],
+2
View File
@@ -1,3 +1,5 @@
// Control Math Utilities
// Purpose: Contains numeric transforms for joystick/keyboard input normalization and shaping. Scope: Implements deadzone, clamp, and mixing math used by control dispatch logic.
/* global Buffer */
import { DRIVE_LIMITS } from './constants.js';
+2
View File
@@ -1,3 +1,5 @@
// Control State Reducer
// Purpose: Implements reducer transitions for control-system runtime state. Scope: Centralizes deterministic state updates for input, mode, and dispatch events.
import { DEFAULT_KEYMAP, DEFAULT_MACROS, SONG_DEFAULT_NOTE } from './constants.js';
function createDriveState() {
+2
View File
@@ -1,3 +1,5 @@
// Control Module Exports
// Purpose: Re-exports control context/providers and input managers from one entrypoint. Scope: Keeps control imports stable and concise for app/module consumers.
export { ControlSystemProvider, useControlSystem } from './ControlContext.jsx';
export { default as KeyboardInputManager } from './inputs/KeyboardInputManager.jsx';
export { default as GamepadInputManager } from './inputs/GamepadInputManager.jsx';
@@ -1,3 +1,5 @@
// Gamepad Input Manager
// Purpose: Converts polled gamepad state into normalized control actions/commands. Scope: Integrates bindings, deadzone math, and dispatch callbacks for driving.
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useControlSystem } from '../ControlContext.jsx';
import { useSettingsNamespace } from '../../settings/index.js';
@@ -1,3 +1,5 @@
// Keyboard Input Manager
// Purpose: Captures and translates keyboard events into normalized control intents. Scope: Owns keydown/keyup listeners and dispatch coordination for drive controls.
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useControlSystem } from '../ControlContext.jsx';
import { useChat } from '../../context/ChatContext.jsx';
@@ -1,3 +1,5 @@
// Gamepad Bindings
// Purpose: Defines default gamepad axis/button-to-action mappings and lookup helpers. Scope: Supplies binding metadata for gamepad input manager and settings UI.
const CURVE_EXPO = 1.6;
export function getPadSignature(pad) {
+2
View File
@@ -1,3 +1,5 @@
// Gamepad Hub Runtime
// Purpose: Tracks connected gamepads and polls input state for downstream handlers. Scope: Encapsulates browser Gamepad API access and per-frame update orchestration.
import { useEffect, useState } from 'react';
import { getPadSignature } from './gamepadBindings.js';
@@ -1,3 +1,5 @@
// Input Focus Utilities
// Purpose: Handles focus/blur guards so controls only capture input when appropriate. Scope: Prevents accidental command capture while typing or using form elements.
const TEXT_INPUT_TYPES = new Set([
'',
'text',
@@ -1,3 +1,5 @@
// Keyboard Capture Lock Helper
// Purpose: Coordinates global keyboard-capture lock state across UI regions. Scope: Ensures only intended surfaces receive keyboard control events at runtime.
let keyboardCaptureLocked = false;
export function setKeyboardCaptureLocked(value) {
+2
View File
@@ -1,3 +1,5 @@
// Keymap Utilities
// Purpose: Normalizes key binding definitions and lookup behavior for control settings. Scope: Provides conversion/validation helpers for keyboard mapping workflows.
const KEY_ALIASES = {
'{': '[',
'}': ']',
+2
View File
@@ -1,3 +1,5 @@
// Overcurrent Limiter Hook/Utility
// Purpose: Applies client-side overcurrent guard logic to reduce harmful command spikes. Scope: Tracks limiter state and exposes gated dispatch behavior to controls.
import { useEffect, useMemo, useRef, useState } from 'react';
import { useTelemetryFrame } from '../context/TelemetryContext.jsx';
import { useSessionSelector } from '../context/SessionContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Help Content Definitions
// Purpose: Stores static/dynamic help text content displayed by help UI components. Scope: Central content source for onboarding instructions and control references.
export const HELP_LAYOUTS = ['desktop', 'mobile-portrait', 'mobile-landscape'];
// Block-based help content; each layout defines a hero plus main/aside blocks.
+2
View File
@@ -1,3 +1,5 @@
// Hook: useDefaultNickname
// Purpose: Computes and applies fallback nickname behavior for unauthenticated/new sessions. Scope: Wraps nickname initialization policy and side effects.
import { useEffect, useRef } from 'react';
import { useSettingsNamespace } from '../settings/index.js';
import { useSessionActions } from '../context/SessionContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useDockIr
// Purpose: Tracks dock IR telemetry/status values for docking-related UI indicators. Scope: Converts telemetry feed updates into component-friendly reactive state.
import { useEffect, useMemo, useState } from 'react';
const HOLD_MS = 650;
+2
View File
@@ -1,3 +1,5 @@
// Hook: useFullscreenPrompt
// Purpose: Manages fullscreen prompt visibility and dismissal logic across screen sizes/devices. Scope: Provides reusable fullscreen UX state and action handlers.
import { useCallback, useEffect, useMemo, useState } from 'react';
const SESSION_KEY = 'fullscreenPromptDismissed';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useHudMapSetting
// Purpose: Reads and persists HUD map visibility/preferences via settings namespaces. Scope: Exposes a small stateful API for map toggle interactions.
import { useSettingsNamespace } from '../settings/index.js';
export function useHudMapSetting() {
@@ -1,3 +1,5 @@
// Hook: useRoomCameraSnapshots
// Purpose: Subscribes to room camera snapshot updates and tracks latest image payloads. Scope: Normalizes snapshot event handling for room camera display components.
import { useEffect, useMemo, useRef, useState } from 'react';
import { useSocket } from '../context/SocketContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useRoverSnapshots
// Purpose: Subscribes to rover snapshot streams and stores latest per-rover image states. Scope: Manages socket request/subscription lifecycle and data normalization.
import { useEffect, useMemo, useRef, useState } from 'react';
import { useSocket } from '../context/SocketContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useSpectatorMode
// Purpose: Encapsulates spectator mode detection and toggle behavior for controls/UI gating. Scope: Derives spectator-specific flags from session and route state.
import { useEffect, useState } from 'react';
import { useSession } from '../context/SessionContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useUserIdentitySync
// Purpose: Keeps local identity state synchronized with server session/auth updates. Scope: Handles identity hydration, change propagation, and persistence touch points.
import { useCallback, useEffect, useRef } from 'react';
import { useSessionActions, useSessionSelector } from '../context/SessionContext.jsx';
import { useSocket } from '../context/SocketContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Hook: useVideoRequests
// Purpose: Coordinates client-side video stream request intents and authorization timing. Scope: Provides reusable request helpers for rover and room video consumers.
import { useEffect, useMemo, useRef, useState } from 'react';
import { useSocket } from '../context/SocketContext.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Battery Utility Library
// Purpose: Provides battery normalization, threshold classification, and display helpers. Scope: Keeps battery rendering/math consistent across UI components.
export const WARN_DISPLAY_PERCENT = 10;
export function buildBatteryVisual({ batteryState = null, charge = null, config = null }) {
+2
View File
@@ -1,3 +1,5 @@
// Rover Color Utility
// Purpose: Maps rover identity/state to deterministic UI color choices. Scope: Supplies shared color resolution helpers for lists, badges, and overlays.
const HEX_RE = /^#[0-9A-Fa-f]{6}$/;
export function normalizeRoverColor(value) {
+2
View File
@@ -1,3 +1,5 @@
// Socket Library Helper
// Purpose: Builds and exports the browser Socket.IO client with shared defaults. Scope: Centralizes connection URL/options so all modules use consistent socket behavior.
import { io } from 'socket.io-client';
import { loadSettings } from '../settings/persistence.js';
+2
View File
@@ -1,3 +1,5 @@
// WHEP Player Helper
// Purpose: Implements browser playback utilities for WHEP/WebRTC media streams. Scope: Manages stream attach/detach, lifecycle cleanup, and error handling hooks.
/* global Buffer */
const RTC_CONFIG = {
+4 -2
View File
@@ -1,3 +1,5 @@
// WebUI Bootstrap Entry
// Purpose: Boots the React application and mounts global providers/router roots. Scope: Defines top-level route wiring and root render lifecycle for the browser app.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
@@ -7,8 +9,8 @@ import { SocketProvider } from './context/SocketContext.jsx'
import { SessionProvider } from './context/SessionContext.jsx'
import { TelemetryProvider } from './context/TelemetryContext.jsx'
import { ChatProvider } from './context/ChatContext.jsx'
import SpectatorApp from './spectate/SpectatorApp.jsx'
import MiniSummaryApp from './mini/MiniSummaryApp.jsx'
import SpectatorApp from './spectate/SpectatorApp/SpectatorAppRoot.jsx'
import MiniSummaryApp from './mini/MiniSummaryApp/MiniSummaryAppRoot.jsx'
import { SettingsProvider } from './settings/index.js'
import DeterrenceChaos from './components/DeterrenceChaos/index.jsx'
-3
View File
@@ -1,3 +0,0 @@
import MiniSummaryAppRoot from './MiniSummaryApp/MiniSummaryAppRoot.jsx';
export default MiniSummaryAppRoot;
+2
View File
@@ -1,3 +1,5 @@
// Settings Provider
// Purpose: Supplies app-wide settings state and namespace-scoped update APIs. Scope: Bridges persistence helpers with React context for consistent settings access.
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { loadSettings, saveSettings } from './persistence.js';
+2
View File
@@ -1,2 +1,4 @@
// Settings Constants
// Purpose: Defines keys/defaults used by the persisted settings subsystem. Scope: Centralizes stable identifiers and fallback values for settings storage.
export const SETTINGS_COOKIE = 'roverSettings';
export const SETTINGS_MAX_AGE = 60 * 60 * 24 * 365; // 1 year
+2
View File
@@ -1 +1,3 @@
// Settings Module Exports
// Purpose: Re-exports settings provider and hooks from a single import path. Scope: Keeps settings consumers decoupled from internal file layout.
export { SettingsProvider, useSettings, useSettingsNamespace } from './SettingsProvider.jsx';
+2
View File
@@ -1,3 +1,5 @@
// Settings Namespaces
// Purpose: Defines namespace identifiers used to segment persisted settings data. Scope: Prevents key collisions and standardizes settings lookup domains.
export const INPUT_SETTINGS_DEFAULTS = {
keyboard: {
baseSpeed: 250,
+2
View File
@@ -1,3 +1,5 @@
// Settings Persistence
// Purpose: Implements local persistence read/write behavior for settings namespaces. Scope: Encapsulates storage IO, parsing guards, and migration-safe defaults.
import { SETTINGS_COOKIE, SETTINGS_MAX_AGE } from './constants.js';
function parseCookieValue(raw) {
-3
View File
@@ -1,3 +0,0 @@
import SpectatorAppRoot from './SpectatorApp/SpectatorAppRoot.jsx';
export default SpectatorAppRoot;