diff --git a/BACKUPS/FIRST_PHASE/README_FIRST_PHASE.md b/BACKUPS/FIRST_PHASE/README_FIRST_PHASE.md
new file mode 100644
index 000000000..e609fe1c9
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/README_FIRST_PHASE.md
@@ -0,0 +1,42 @@
+# FIRST PHASE BACKUP
+
+**Date:** $(date)
+**Status:** LOCKED - Working State
+
+## Features Included:
+- ✅ Vendor Management System
+- ✅ YFinance Integration
+- ✅ Trading Dashboard with Tabs
+- ✅ Market Data Fetching
+- ✅ Analytics & Bulk Download
+- ✅ Admin Tab with Code Viewer
+- ✅ Error Boundaries
+- ✅ Fault Isolation
+
+## Architecture:
+- **Core System:** VendorManager, BaseVendorAdapter
+- **Vendors:** ExampleVendorA, ExampleVendorB, YFinanceVendor
+- **Components:** TradingDashboard, YFinanceComponents, AdminComponents
+- **UI:** Responsive design with tabbed interface
+
+## Restore Instructions:
+```bash
+# To restore this phase:
+rm -rf src/
+cp -r BACKUPS/FIRST_PHASE/src/ ./
+cp BACKUPS/FIRST_PHASE/package.json ./
+cp BACKUPS/FIRST_PHASE/vite.config.js ./
+cp BACKUPS/FIRST_PHASE/index.html ./
+```
+
+## Key Files:
+- src/core/VendorManager.js
+- src/core/BaseVendorAdapter.js
+- src/vendors/YFinanceVendor.js
+- src/components/TradingDashboard.jsx
+- src/components/YFinanceComponents.jsx
+- src/components/AdminComponents.jsx
+- src/App.jsx
+- src/App.css
+
+**⚠️ DO NOT MODIFY THIS BACKUP ⚠️**
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/index.html b/BACKUPS/FIRST_PHASE/index.html
new file mode 100644
index 000000000..452ca1f32
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
diff --git a/BACKUPS/FIRST_PHASE/package.json b/BACKUPS/FIRST_PHASE/package.json
new file mode 100644
index 000000000..5e1b6b8c4
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "codespaces-react",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^14.4.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "web-vitals": "^3.1.0"
+ },
+ "overrides": {
+ "@svgr/webpack": "^8.0.1",
+ "@adobe/css-tools": "^4.3.1",
+ "postcss": "^8.4.31"
+ },
+ "scripts": {
+ "start": "BROWSER=none WDS_SOCKET_PORT=0 vite --port 3000",
+ "build": "vite build",
+ "preview": "vite preview",
+ "test": "vitest"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.7.0",
+ "jsdom": "^26.1.0",
+ "vite": "^6.3.6",
+ "vitest": "^3.0.7"
+ }
+}
diff --git a/BACKUPS/FIRST_PHASE/src/App.css b/BACKUPS/FIRST_PHASE/src/App.css
new file mode 100644
index 000000000..f73ff0f34
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/App.css
@@ -0,0 +1,387 @@
+.trading-dashboard {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+}
+
+.dashboard-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30px;
+ padding-bottom: 20px;
+ border-bottom: 2px solid #e0e0e0;
+}
+
+.dashboard-header h1 {
+ margin: 0;
+ color: #333;
+ font-size: 2rem;
+}
+
+.vendor-selector {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+ min-width: 150px;
+}
+
+.tab-navigation {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.tab {
+ padding: 12px 24px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ color: #666;
+ border-bottom: 3px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.tab:hover {
+ color: #333;
+ background-color: #f5f5f5;
+}
+
+.tab.active {
+ color: #007acc;
+ border-bottom-color: #007acc;
+}
+
+.dashboard-content {
+ min-height: 400px;
+}
+
+.tab-content {
+ padding: 20px;
+ background: #f9f9f9;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.tab-content h2 {
+ margin-top: 0;
+ color: #333;
+}
+
+.error-boundary {
+ padding: 20px;
+ background: #fff3cd;
+ border: 1px solid #ffeaa7;
+ border-radius: 8px;
+ text-align: center;
+}
+
+.error-boundary h3 {
+ color: #856404;
+ margin-top: 0;
+}
+
+.error-boundary button {
+ padding: 8px 16px;
+ background: #007acc;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-top: 10px;
+}
+
+.error-boundary button:hover {
+ background: #005a9e;
+}
+
+.fetch-controls, .analytics-controls, .bulk-controls {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+ margin-bottom: 20px;
+}
+
+.control-row {
+ display: flex;
+ gap: 15px;
+ margin-bottom: 15px;
+ flex-wrap: wrap;
+}
+
+.control-group {
+ flex: 1;
+ min-width: 150px;
+}
+
+.control-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: 500;
+ font-size: 14px;
+}
+
+.control-group input, .control-group select {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+}
+
+.control-group input[type="checkbox"] {
+ width: auto;
+ margin-right: 8px;
+}
+
+.fetch-btn {
+ background: #007acc;
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ width: 100%;
+ margin-top: 10px;
+}
+
+.fetch-btn:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
+
+.fetch-btn:hover:not(:disabled) {
+ background: #005a9e;
+}
+
+.quote-display {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.price-info {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin: 10px 0;
+}
+
+.price {
+ font-size: 2rem;
+ font-weight: bold;
+ color: #333;
+}
+
+.change.positive {
+ color: #28a745;
+}
+
+.change.negative {
+ color: #dc3545;
+}
+
+.historical-summary {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ margin-top: 15px;
+}
+
+.historical-summary p {
+ margin: 5px 0;
+ font-size: 14px;
+}
+
+.analytics-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 15px;
+ margin-top: 20px;
+}
+
+.metric {
+ background: white;
+ padding: 15px;
+ border-radius: 6px;
+ border: 1px solid #e0e0e0;
+ text-align: center;
+}
+
+.metric label {
+ display: block;
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 5px;
+}
+
+.metric span {
+ font-size: 16px;
+ font-weight: bold;
+}
+
+.volatility.high, .recommendation.sell {
+ color: #dc3545;
+}
+
+.volatility.medium, .recommendation.hold {
+ color: #ffc107;
+}
+
+.volatility.low, .recommendation.buy, .trend.up {
+ color: #28a745;
+}
+
+.trend.down {
+ color: #dc3545;
+}
+
+.bulk-downloader {
+ margin-top: 30px;
+ padding: 20px;
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.download-results {
+ margin-top: 15px;
+ padding: 10px;
+ background: #d4edda;
+ border: 1px solid #c3e6cb;
+ border-radius: 4px;
+ color: #155724;
+}
+
+.admin-nav {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
+}
+
+.admin-btn {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ background: white;
+ cursor: pointer;
+ border-radius: 4px;
+}
+
+.admin-btn.active {
+ background: #007acc;
+ color: white;
+ border-color: #007acc;
+}
+
+.code-viewer {
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.code-tabs {
+ display: flex;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.code-tab {
+ padding: 12px 20px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-bottom: 3px solid transparent;
+}
+
+.code-tab.active {
+ background: #f8f9fa;
+ border-bottom-color: #007acc;
+}
+
+.code-display {
+ padding: 20px;
+}
+
+.code-block {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ overflow-x: auto;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 13px;
+ line-height: 1.4;
+ border: 1px solid #e9ecef;
+}
+
+.vendor-status {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.status-btn {
+ background: #28a745;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-bottom: 20px;
+}
+
+.status-grid {
+ display: grid;
+ gap: 15px;
+}
+
+.status-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ background: #f8f9fa;
+ border-radius: 4px;
+}
+
+.status-item label {
+ font-weight: 500;
+}
+
+.connected {
+ color: #28a745;
+}
+
+.disconnected {
+ color: #dc3545;
+}
+
+.capabilities {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.capability {
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.capability.enabled {
+ background: #d4edda;
+ color: #155724;
+}
+
+.capability.disabled {
+ background: #f8d7da;
+ color: #721c24;
+}
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/App.jsx b/BACKUPS/FIRST_PHASE/src/App.jsx
new file mode 100644
index 000000000..f3a1bf21a
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/App.jsx
@@ -0,0 +1,24 @@
+import React, { useEffect } from 'react';
+import './App.css';
+import TradingDashboard from './components/TradingDashboard';
+import VendorManager from './core/VendorManager';
+import ExampleVendorA from './vendors/ExampleVendorA';
+import ExampleVendorB from './vendors/ExampleVendorB';
+import YFinanceVendor from './vendors/YFinanceVendor';
+
+function App() {
+ useEffect(() => {
+ // Register vendors on app startup
+ VendorManager.registerVendor('vendorA', new ExampleVendorA());
+ VendorManager.registerVendor('vendorB', new ExampleVendorB());
+ VendorManager.registerVendor('yfinance', new YFinanceVendor());
+ }, []);
+
+ return (
+
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/App.test.jsx b/BACKUPS/FIRST_PHASE/src/App.test.jsx
new file mode 100644
index 000000000..5e9824933
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/App.test.jsx
@@ -0,0 +1,9 @@
+import { expect, test } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import App from './App';
+
+test('renders learn react link', () => {
+ render();
+ const linkElement = screen.getByText(/learn react/i);
+ expect(linkElement).toBeDefined();
+});
diff --git a/BACKUPS/FIRST_PHASE/src/components/AdminComponents.jsx b/BACKUPS/FIRST_PHASE/src/components/AdminComponents.jsx
new file mode 100644
index 000000000..c1dfce7d8
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/components/AdminComponents.jsx
@@ -0,0 +1,291 @@
+import React, { useState } from 'react';
+import VendorManager from '../core/VendorManager';
+
+export const CodeViewer = ({ vendor }) => {
+ const [activeCode, setActiveCode] = useState('fetch');
+
+ const codeExamples = {
+ fetch: {
+ title: 'Data Fetching Code',
+ code: `// Market Data Fetch
+const fetchMarketData = async (symbol, interval = '1d') => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseYahooResponse(data, symbol);
+};
+
+// Historical Data Fetch
+const fetchHistoricalData = async (symbol, interval, period) => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=\${period}\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseHistoricalData(data, symbol);
+};
+
+// Bulk Download
+const bulkDownload = async (symbols, intervals, options) => {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ const data = await fetchHistoricalData(symbol, interval, options.period);
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ }
+ }
+
+ // Rate limiting
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return results;
+};`
+ },
+ parser: {
+ title: 'Data Parser Code',
+ code: `// Yahoo Response Parser
+const parseYahooResponse = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+};
+
+// Historical Data Parser
+const parseHistoricalData = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+};`
+ },
+ analytics: {
+ title: 'Analytics Code',
+ code: `// Volatility Calculator
+const calculateVolatility = (dailyData, weeklyData) => {
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+};
+
+// Recommendation Generator
+const generateRecommendation = (data) => {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+};
+
+// Analytics Fetch
+const getAnalytics = async (symbol, timeframe = '1mo') => {
+ const [daily, weekly] = await Promise.all([
+ getMarketData(symbol, '1d'),
+ getMarketData(symbol, '1wk')
+ ]);
+
+ return {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ volatility: calculateVolatility(daily.data, weekly.data),
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ recommendation: generateRecommendation(daily.data)
+ };
+};`
+ },
+ vendor: {
+ title: 'Vendor Adapter Code',
+ code: `// YFinance Vendor Class
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = \`\${symbol}_\${interval}\`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ const url = \`\${this.config.baseUrl}\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+}`
+ }
+ };
+
+ return (
+
+
+ {Object.entries(codeExamples).map(([key, example]) => (
+
+ ))}
+
+
+
+
{codeExamples[activeCode].title}
+
+ {codeExamples[activeCode].code}
+
+
+
+ );
+};
+
+export const VendorStatus = ({ vendor }) => {
+ const [status, setStatus] = useState(null);
+
+ const checkStatus = async () => {
+ try {
+ const vendorInstance = VendorManager.getVendor(vendor);
+ const capabilities = VendorManager.getVendorCapabilities(vendor);
+
+ setStatus({
+ name: vendorInstance?.name || 'Unknown',
+ connected: vendorInstance?.isConnected || false,
+ capabilities,
+ cacheSize: vendorInstance?.cache?.size || 0
+ });
+ } catch (error) {
+ setStatus({ error: error.message });
+ }
+ };
+
+ return (
+
+
+
+ {status && (
+
+ {status.error ? (
+
Error: {status.error}
+ ) : (
+
+
+
+ {status.name}
+
+
+
+
+ {status.connected ? 'Connected' : 'Disconnected'}
+
+
+
+
+ {status.cacheSize} items
+
+
+
+
+ {Object.entries(status.capabilities).map(([cap, enabled]) => (
+
+ {cap}: {enabled ? '✓' : '✗'}
+
+ ))}
+
+
+
+ )}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/components/ErrorBoundary.jsx b/BACKUPS/FIRST_PHASE/src/components/ErrorBoundary.jsx
new file mode 100644
index 000000000..9028075a8
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/components/ErrorBoundary.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+class ErrorBoundary extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error, errorInfo) {
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+
Something went wrong
+
{this.props.fallbackMessage || 'This section is temporarily unavailable'}
+
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/components/TradingDashboard.jsx b/BACKUPS/FIRST_PHASE/src/components/TradingDashboard.jsx
new file mode 100644
index 000000000..8b6db8b21
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/components/TradingDashboard.jsx
@@ -0,0 +1,170 @@
+import React, { useState, useEffect } from 'react';
+import ErrorBoundary from './ErrorBoundary';
+import VendorManager from '../core/VendorManager';
+import { YFinanceMarketData, YFinanceAnalytics, YFinanceBulkDownloader } from './YFinanceComponents';
+import { CodeViewer, VendorStatus } from './AdminComponents';
+
+const TradingDashboard = () => {
+ const [activeTab, setActiveTab] = useState('market');
+ const [vendors, setVendors] = useState([]);
+ const [selectedVendor, setSelectedVendor] = useState('');
+
+ useEffect(() => {
+ setVendors(VendorManager.getAllVendors());
+ if (VendorManager.getAllVendors().length > 0) {
+ setSelectedVendor(VendorManager.getAllVendors()[0]);
+ }
+ }, []);
+
+ const tabs = [
+ { id: 'market', label: 'Market Data', capability: 'marketData' },
+ { id: 'orders', label: 'Orders', capability: 'orderManagement' },
+ { id: 'portfolio', label: 'Portfolio', capability: 'portfolio' },
+ { id: 'analytics', label: 'Analytics', capability: 'analytics' },
+ { id: 'admin', label: 'Admin', capability: 'admin' }
+ ];
+
+ const getAvailableTabs = () => {
+ if (!selectedVendor) return [];
+ const capabilities = VendorManager.getVendorCapabilities(selectedVendor);
+ return tabs.filter(tab => tab.capability === 'admin' || capabilities[tab.capability]);
+ };
+
+ const renderTabContent = () => {
+ const availableTabs = getAvailableTabs();
+ const currentTab = availableTabs.find(tab => tab.id === activeTab);
+
+ if (!currentTab) {
+ return Feature not available for selected vendor
;
+ }
+
+ switch (activeTab) {
+ case 'market':
+ return ;
+ case 'orders':
+ return ;
+ case 'portfolio':
+ return ;
+ case 'analytics':
+ return ;
+ case 'admin':
+ return ;
+ default:
+ return Select a tab
;
+ }
+ };
+
+ return (
+
+
+ Trading Dashboard
+
+
+
+
+
+
+
+ {renderTabContent()}
+
+
+
+ );
+};
+
+const MarketDataTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Market Data - Yahoo Finance
+
+
+ );
+ }
+ return (
+
+
Market Data - {vendor}
+
Market data functionality for {vendor}
+
+ );
+};
+
+const OrdersTab = ({ vendor }) => (
+
+
Order Management - {vendor}
+
Order management functionality for {vendor}
+
+);
+
+const PortfolioTab = ({ vendor }) => (
+
+
Portfolio - {vendor}
+
Portfolio functionality for {vendor}
+
+);
+
+const AnalyticsTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Analytics - Yahoo Finance
+
+
+
+ );
+ }
+ return (
+
+
Analytics - {vendor}
+
Analytics functionality for {vendor}
+
+ );
+};
+
+const AdminTab = ({ vendor }) => {
+ const [activeAdmin, setActiveAdmin] = useState('code');
+
+ return (
+
+
Admin - {vendor}
+
+
+
+
+
+ {activeAdmin === 'code' &&
}
+ {activeAdmin === 'status' &&
}
+
+ );
+};
+
+export default TradingDashboard;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/components/YFinanceComponents.jsx b/BACKUPS/FIRST_PHASE/src/components/YFinanceComponents.jsx
new file mode 100644
index 000000000..a9ece5aec
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/components/YFinanceComponents.jsx
@@ -0,0 +1,339 @@
+import React, { useState, useEffect } from 'react';
+import VendorManager from '../core/VendorManager';
+
+export const YFinanceMarketData = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [assetType, setAssetType] = useState('stocks');
+ const [interval, setInterval] = useState('1d');
+ const [period, setPeriod] = useState('1mo');
+ const [customStart, setCustomStart] = useState('');
+ const [customEnd, setCustomEnd] = useState('');
+ const [useCustomRange, setUseCustomRange] = useState(false);
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const assetTypes = {
+ stocks: { label: 'Stocks', examples: 'AAPL, GOOGL, MSFT' },
+ forex: { label: 'Forex', examples: 'EURUSD=X, GBPUSD=X, USDJPY=X' },
+ crypto: { label: 'Crypto', examples: 'BTC-USD, ETH-USD, ADA-USD' },
+ commodities: { label: 'Commodities', examples: 'GC=F, CL=F, SI=F' },
+ indices: { label: 'Indices', examples: '^GSPC, ^DJI, ^IXIC' }
+ };
+
+ const intervals = ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', '10y', 'ytd', 'max'];
+
+ const fetchData = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ setError(null);
+
+ try {
+ const fetchParams = {
+ symbol: symbol.toUpperCase(),
+ interval,
+ period: useCustomRange ? null : period,
+ start: useCustomRange ? customStart : null,
+ end: useCustomRange ? customEnd : null
+ };
+
+ const result = useCustomRange || period !== '1d'
+ ? await VendorManager.executeVendorMethod(vendor, 'getHistoricalData', fetchParams.symbol, fetchParams.interval, fetchParams.period || '1mo')
+ : await VendorManager.executeVendorMethod(vendor, 'getMarketData', fetchParams.symbol, fetchParams.interval);
+
+ if (result.success) {
+ setData(result.data);
+ } else {
+ setError(result.error);
+ }
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder={assetTypes[assetType].examples}
+ onKeyPress={(e) => e.key === 'Enter' && fetchData()}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {useCustomRange ? (
+
+ ) : (
+
+
+
+
+
+
+ )}
+
+
+
+
+ {error &&
Error: {error}
}
+
+ {data && (
+
+
{data.symbol}
+ {data.price ? (
+
+ ${data.price?.toFixed(2)}
+ = 0 ? 'positive' : 'negative'}`}>
+ {data.change >= 0 ? '+' : ''}{data.change?.toFixed(2)}
+ ({data.changePercent?.toFixed(2)}%)
+
+
+ ) : null}
+ {data.data && (
+
+
Historical data: {data.data.length} records
+
Latest: ${data.data[data.data.length - 1]?.close?.toFixed(2)}
+
+ )}
+
+ )}
+
+ );
+};
+
+export const YFinanceAnalytics = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [timeframe, setTimeframe] = useState('1mo');
+ const [analytics, setAnalytics] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const timeframes = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y'];
+
+ const fetchAnalytics = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(vendor, 'getAnalytics', symbol.toUpperCase(), timeframe);
+ if (result.success) {
+ setAnalytics(result.data);
+ }
+ } catch (err) {
+ console.error('Analytics error:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder="Enter symbol for analysis"
+ onKeyPress={(e) => e.key === 'Enter' && fetchAnalytics()}
+ />
+
+
+
+
+
+
+
+
+ {analytics && (
+
+
Analysis for {analytics.symbol} ({timeframe})
+
+
+
+ ${analytics.price?.toFixed(2)}
+
+
+
+
+ {analytics.volatility}
+
+
+
+
+
+ {analytics.weeklyTrend}
+
+
+
+
+
+ {analytics.recommendation}
+
+
+
+
+ )}
+
+ );
+};
+
+export const YFinanceBulkDownloader = ({ vendor }) => {
+ const [symbols, setSymbols] = useState('AAPL,GOOGL,MSFT');
+ const [intervals, setIntervals] = useState(['1d']);
+ const [period, setPeriod] = useState('1mo');
+ const [batchSize, setBatchSize] = useState(5);
+ const [downloading, setDownloading] = useState(false);
+ const [results, setResults] = useState(null);
+
+ const availableIntervals = ['1m', '5m', '15m', '1h', '1d', '1wk', '1mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', 'max'];
+
+ const handleBulkDownload = async () => {
+ const symbolList = symbols.split(',').map(s => s.trim().toUpperCase()).filter(s => s);
+ if (symbolList.length === 0) return;
+
+ setDownloading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(
+ vendor,
+ 'bulkDownload',
+ symbolList,
+ intervals,
+ { period, batchSize }
+ );
+ setResults(result);
+ } catch (err) {
+ console.error('Bulk download error:', err);
+ } finally {
+ setDownloading(false);
+ }
+ };
+
+ return (
+
+
Bulk Historical Data Download
+
+
+
+ setSymbols(e.target.value)}
+ placeholder="AAPL,GOOGL,MSFT,BTC-USD,EURUSD=X"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ setBatchSize(parseInt(e.target.value))}
+ min="1"
+ max="50"
+ />
+
+
+
+
+
+ {results && (
+
+
Download Complete
+
Downloaded data for {Object.keys(results.data || {}).length} symbols
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/core/BaseVendorAdapter.js b/BACKUPS/FIRST_PHASE/src/core/BaseVendorAdapter.js
new file mode 100644
index 000000000..f5f979cd7
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/core/BaseVendorAdapter.js
@@ -0,0 +1,51 @@
+export class BaseVendorAdapter {
+ constructor(name, config = {}) {
+ this.name = name;
+ this.config = config;
+ this.isConnected = false;
+ }
+
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ throw new Error('connect() must be implemented by vendor adapter');
+ }
+
+ async disconnect() {
+ this.isConnected = false;
+ }
+
+ async getMarketData(symbol) {
+ throw new Error('getMarketData() not implemented');
+ }
+
+ async placeOrder(orderData) {
+ throw new Error('placeOrder() not implemented');
+ }
+
+ async getPortfolio() {
+ throw new Error('getPortfolio() not implemented');
+ }
+
+ async getAnalytics(symbol) {
+ throw new Error('getAnalytics() not implemented');
+ }
+
+ handleError(error, context) {
+ console.error(`${this.name} Error in ${context}:`, error);
+ return {
+ success: false,
+ error: error.message,
+ vendor: this.name,
+ context
+ };
+ }
+}
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/core/VendorManager.js b/BACKUPS/FIRST_PHASE/src/core/VendorManager.js
new file mode 100644
index 000000000..b4bafabc8
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/core/VendorManager.js
@@ -0,0 +1,54 @@
+class VendorManager {
+ constructor() {
+ this.vendors = new Map();
+ this.capabilities = new Map();
+ }
+
+ registerVendor(vendorId, vendorAdapter) {
+ try {
+ if (!vendorAdapter.name || !vendorAdapter.getCapabilities) {
+ throw new Error(`Invalid vendor adapter for ${vendorId}`);
+ }
+
+ this.vendors.set(vendorId, vendorAdapter);
+ this.capabilities.set(vendorId, vendorAdapter.getCapabilities());
+ return true;
+ } catch (error) {
+ console.error(`Failed to register vendor ${vendorId}:`, error);
+ return false;
+ }
+ }
+
+ getVendor(vendorId) {
+ return this.vendors.get(vendorId);
+ }
+
+ getVendorCapabilities(vendorId) {
+ return this.capabilities.get(vendorId) || {};
+ }
+
+ getAllVendors() {
+ return Array.from(this.vendors.keys());
+ }
+
+ getVendorsWithCapability(capability) {
+ return Array.from(this.vendors.keys()).filter(vendorId =>
+ this.getVendorCapabilities(vendorId)[capability]
+ );
+ }
+
+ async executeVendorMethod(vendorId, method, ...args) {
+ try {
+ const vendor = this.getVendor(vendorId);
+ if (!vendor || !vendor[method]) {
+ throw new Error(`Method ${method} not available for vendor ${vendorId}`);
+ }
+ return await vendor[method](...args);
+ } catch (error) {
+ console.error(`Error executing ${method} for vendor ${vendorId}:`, error);
+ throw error;
+ }
+ }
+}
+
+export default new VendorManager();
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/index.css b/BACKUPS/FIRST_PHASE/src/index.css
new file mode 100644
index 000000000..ec2585e8c
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/index.css
@@ -0,0 +1,13 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
diff --git a/BACKUPS/FIRST_PHASE/src/index.jsx b/BACKUPS/FIRST_PHASE/src/index.jsx
new file mode 100644
index 000000000..d563c0fb1
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/index.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
+
+
+
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();
diff --git a/BACKUPS/FIRST_PHASE/src/logo.svg b/BACKUPS/FIRST_PHASE/src/logo.svg
new file mode 100644
index 000000000..9dfc1c058
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/reportWebVitals.js b/BACKUPS/FIRST_PHASE/src/reportWebVitals.js
new file mode 100644
index 000000000..5253d3ad9
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/reportWebVitals.js
@@ -0,0 +1,13 @@
+const reportWebVitals = onPerfEntry => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/BACKUPS/FIRST_PHASE/src/setupTests.js b/BACKUPS/FIRST_PHASE/src/setupTests.js
new file mode 100644
index 000000000..8f2609b7b
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/setupTests.js
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/BACKUPS/FIRST_PHASE/src/utils/VendorRegistry.js b/BACKUPS/FIRST_PHASE/src/utils/VendorRegistry.js
new file mode 100644
index 000000000..cb45320c8
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/utils/VendorRegistry.js
@@ -0,0 +1,56 @@
+import VendorManager from '../core/VendorManager';
+
+export const registerNewVendor = (vendorId, VendorClass, config = {}) => {
+ try {
+ const vendorInstance = new VendorClass(config);
+ const success = VendorManager.registerVendor(vendorId, vendorInstance);
+
+ if (success) {
+ console.log(`✅ Vendor ${vendorId} registered successfully`);
+ return true;
+ } else {
+ console.error(`❌ Failed to register vendor ${vendorId}`);
+ return false;
+ }
+ } catch (error) {
+ console.error(`❌ Error registering vendor ${vendorId}:`, error);
+ return false;
+ }
+};
+
+export const getVendorInfo = (vendorId) => {
+ const vendor = VendorManager.getVendor(vendorId);
+ const capabilities = VendorManager.getVendorCapabilities(vendorId);
+
+ return {
+ exists: !!vendor,
+ name: vendor?.name || 'Unknown',
+ capabilities,
+ isConnected: vendor?.isConnected || false
+ };
+};
+
+export const testVendor = async (vendorId) => {
+ try {
+ const vendor = VendorManager.getVendor(vendorId);
+ if (!vendor) {
+ return { success: false, error: 'Vendor not found' };
+ }
+
+ const connectionResult = await vendor.connect();
+ const capabilities = vendor.getCapabilities();
+
+ return {
+ success: true,
+ connection: connectionResult,
+ capabilities,
+ vendor: vendor.name
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error.message,
+ vendor: vendorId
+ };
+ }
+};
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorA.js b/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorA.js
new file mode 100644
index 000000000..46f8cdd42
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorA.js
@@ -0,0 +1,76 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorA extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor A', {
+ apiUrl: 'https://api.vendora.com',
+ apiKey: 'your-api-key'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: true,
+ portfolio: true,
+ analytics: false,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 100,
+ change: Math.random() * 10 - 5,
+ volume: Math.floor(Math.random() * 1000000)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async placeOrder(orderData) {
+ try {
+ return {
+ success: true,
+ orderId: `VA_${Date.now()}`,
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ async getPortfolio() {
+ try {
+ return {
+ success: true,
+ data: {
+ totalValue: 50000,
+ positions: [
+ { symbol: 'AAPL', quantity: 10, value: 1500 },
+ { symbol: 'GOOGL', quantity: 5, value: 12500 }
+ ]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+}
+
+export default ExampleVendorA;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorB.js b/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorB.js
new file mode 100644
index 000000000..66167fc33
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/vendors/ExampleVendorB.js
@@ -0,0 +1,66 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorB extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor B', {
+ baseUrl: 'https://vendorb-api.com/v2',
+ token: 'bearer-token'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 200,
+ bid: Math.random() * 190,
+ ask: Math.random() * 210,
+ timestamp: Date.now()
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ rsi: Math.random() * 100,
+ macd: Math.random() * 5 - 2.5,
+ sma20: Math.random() * 150,
+ sma50: Math.random() * 140,
+ recommendation: ['BUY', 'SELL', 'HOLD'][Math.floor(Math.random() * 3)]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+}
+
+export default ExampleVendorB;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/vendors/VendorTemplate.js b/BACKUPS/FIRST_PHASE/src/vendors/VendorTemplate.js
new file mode 100644
index 000000000..c411953db
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/vendors/VendorTemplate.js
@@ -0,0 +1,141 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+/**
+ * Template for creating new vendor adapters
+ * Copy this file and implement your vendor-specific logic
+ */
+class VendorTemplate extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Vendor Name', {
+ apiUrl: config.apiUrl || '',
+ apiKey: config.apiKey || '',
+ ...config
+ });
+ }
+
+ /**
+ * Define what this vendor can do
+ * Set to true only for features this vendor supports
+ */
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ /**
+ * Connect to vendor API
+ */
+ async connect() {
+ try {
+ // TODO: Implement your connection logic
+ // Example: await fetch(this.config.apiUrl + '/connect')
+
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ /**
+ * Get market data for a symbol
+ * Only implement if marketData capability is true
+ */
+ async getMarketData(symbol) {
+ try {
+ // TODO: Implement your market data API call
+ // Example:
+ // const response = await fetch(`${this.config.apiUrl}/market/${symbol}`);
+ // const data = await response.json();
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: 0,
+ change: 0,
+ volume: 0
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ /**
+ * Place an order
+ * Only implement if orderManagement capability is true
+ */
+ async placeOrder(orderData) {
+ try {
+ // TODO: Implement your order placement logic
+
+ return {
+ success: true,
+ orderId: '',
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ /**
+ * Get portfolio data
+ * Only implement if portfolio capability is true
+ */
+ async getPortfolio() {
+ try {
+ // TODO: Implement your portfolio API call
+
+ return {
+ success: true,
+ data: {
+ totalValue: 0,
+ positions: []
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+
+ /**
+ * Get analytics for a symbol
+ * Only implement if analytics capability is true
+ */
+ async getAnalytics(symbol) {
+ try {
+ // TODO: Implement your analytics API call
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ indicators: {}
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ /**
+ * Add any custom methods your vendor needs
+ */
+ async customMethod() {
+ try {
+ // Your custom implementation
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'customMethod');
+ }
+ }
+}
+
+export default VendorTemplate;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/src/vendors/YFinanceVendor.js b/BACKUPS/FIRST_PHASE/src/vendors/YFinanceVendor.js
new file mode 100644
index 000000000..963720653
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/src/vendors/YFinanceVendor.js
@@ -0,0 +1,232 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ // Test connection with a simple quote
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = `${symbol}_${interval}`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ // Use Yahoo Finance API directly (simplified version of the Python script logic)
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=1d`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ // Cache the result
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getHistoricalData(symbol, interval = '1d', period = '1mo') {
+ try {
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=${period}`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return {
+ success: true,
+ data: this.parseHistoricalData(data, symbol)
+ };
+ } catch (error) {
+ return this.handleError(error, 'getHistoricalData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ // Get multiple timeframes for analytics
+ const [daily, weekly] = await Promise.all([
+ this.getMarketData(symbol, '1d'),
+ this.getMarketData(symbol, '1wk')
+ ]);
+
+ if (!daily.success || !weekly.success) {
+ throw new Error('Failed to fetch data for analytics');
+ }
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ marketCap: daily.data.marketCap,
+ pe: daily.data.pe,
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ volatility: this.calculateVolatility(daily.data, weekly.data),
+ recommendation: this.generateRecommendation(daily.data)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ parseYahooResponse(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid response format');
+ }
+
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ marketCap: meta.marketCap || null,
+ pe: meta.trailingPE || null,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse Yahoo response: ${error.message}`);
+ }
+ }
+
+ parseHistoricalData(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid historical data format');
+ }
+
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse historical data: ${error.message}`);
+ }
+ }
+
+ calculateVolatility(dailyData, weeklyData) {
+ // Simple volatility calculation
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+ }
+
+ generateRecommendation(data) {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+ }
+
+ // Bulk download method (adapted from Python script)
+ async bulkDownload(symbols, intervals = ['1d'], options = {}) {
+ try {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ try {
+ const data = await this.getHistoricalData(symbol, interval, options.period || '1mo');
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ } catch (error) {
+ console.warn(`Failed to download ${symbol} ${interval}:`, error);
+ }
+ }
+ }
+
+ // Rate limiting (like the Python script)
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return { success: true, data: results };
+ } catch (error) {
+ return this.handleError(error, 'bulkDownload');
+ }
+ }
+}
+
+export default YFinanceVendor;
\ No newline at end of file
diff --git a/BACKUPS/FIRST_PHASE/vite.config.js b/BACKUPS/FIRST_PHASE/vite.config.js
new file mode 100644
index 000000000..248c2f847
--- /dev/null
+++ b/BACKUPS/FIRST_PHASE/vite.config.js
@@ -0,0 +1,11 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ globals: true,
+ environment: 'jsdom',
+ },
+})
diff --git a/BACKUPS/SECOND_PHASE/README_SECOND_PHASE.md b/BACKUPS/SECOND_PHASE/README_SECOND_PHASE.md
new file mode 100644
index 000000000..5b5303469
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/README_SECOND_PHASE.md
@@ -0,0 +1,37 @@
+# SECOND PHASE BACKUP
+
+**Date:** $(date)
+**Status:** LOCKED - Working State with Code Editor
+
+## Features Added in Second Phase:
+- ✅ Code Refactoring Capability
+- ✅ Live Code Editor in Admin Tab
+- ✅ Version History (5 versions per code section)
+- ✅ Edit/View Mode Toggle
+- ✅ One-click Revert System
+- ✅ Safe Non-destructive Editing
+
+## All First Phase Features:
+- ✅ Vendor Management System
+- ✅ YFinance Integration
+- ✅ Trading Dashboard with Tabs
+- ✅ Market Data Fetching
+- ✅ Analytics & Bulk Download
+- ✅ Admin Tab with Code Viewer
+- ✅ Error Boundaries
+- ✅ Fault Isolation
+
+## New Components:
+- src/components/CodeEditor.jsx
+
+## Restore Instructions:
+```bash
+# To restore this phase:
+rm -rf src/
+cp -r BACKUPS/SECOND_PHASE/src/ ./
+cp BACKUPS/SECOND_PHASE/package.json ./
+cp BACKUPS/SECOND_PHASE/vite.config.js ./
+cp BACKUPS/SECOND_PHASE/index.html ./
+```
+
+**⚠️ DO NOT MODIFY THIS BACKUP ⚠️**
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/index.html b/BACKUPS/SECOND_PHASE/index.html
new file mode 100644
index 000000000..452ca1f32
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
diff --git a/BACKUPS/SECOND_PHASE/package.json b/BACKUPS/SECOND_PHASE/package.json
new file mode 100644
index 000000000..5e1b6b8c4
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "codespaces-react",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^14.4.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "web-vitals": "^3.1.0"
+ },
+ "overrides": {
+ "@svgr/webpack": "^8.0.1",
+ "@adobe/css-tools": "^4.3.1",
+ "postcss": "^8.4.31"
+ },
+ "scripts": {
+ "start": "BROWSER=none WDS_SOCKET_PORT=0 vite --port 3000",
+ "build": "vite build",
+ "preview": "vite preview",
+ "test": "vitest"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@vitejs/plugin-react": "^4.7.0",
+ "jsdom": "^26.1.0",
+ "vite": "^6.3.6",
+ "vitest": "^3.0.7"
+ }
+}
diff --git a/BACKUPS/SECOND_PHASE/src/App.css b/BACKUPS/SECOND_PHASE/src/App.css
new file mode 100644
index 000000000..f7e4a489b
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/App.css
@@ -0,0 +1,488 @@
+.trading-dashboard {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+}
+
+.dashboard-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30px;
+ padding-bottom: 20px;
+ border-bottom: 2px solid #e0e0e0;
+}
+
+.dashboard-header h1 {
+ margin: 0;
+ color: #333;
+ font-size: 2rem;
+}
+
+.vendor-selector {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+ min-width: 150px;
+}
+
+.tab-navigation {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.tab {
+ padding: 12px 24px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ color: #666;
+ border-bottom: 3px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.tab:hover {
+ color: #333;
+ background-color: #f5f5f5;
+}
+
+.tab.active {
+ color: #007acc;
+ border-bottom-color: #007acc;
+}
+
+.dashboard-content {
+ min-height: 400px;
+}
+
+.tab-content {
+ padding: 20px;
+ background: #f9f9f9;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.tab-content h2 {
+ margin-top: 0;
+ color: #333;
+}
+
+.error-boundary {
+ padding: 20px;
+ background: #fff3cd;
+ border: 1px solid #ffeaa7;
+ border-radius: 8px;
+ text-align: center;
+}
+
+.error-boundary h3 {
+ color: #856404;
+ margin-top: 0;
+}
+
+.error-boundary button {
+ padding: 8px 16px;
+ background: #007acc;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-top: 10px;
+}
+
+.error-boundary button:hover {
+ background: #005a9e;
+}
+
+.fetch-controls, .analytics-controls, .bulk-controls {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+ margin-bottom: 20px;
+}
+
+.control-row {
+ display: flex;
+ gap: 15px;
+ margin-bottom: 15px;
+ flex-wrap: wrap;
+}
+
+.control-group {
+ flex: 1;
+ min-width: 150px;
+}
+
+.control-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: 500;
+ font-size: 14px;
+}
+
+.control-group input, .control-group select {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+}
+
+.control-group input[type="checkbox"] {
+ width: auto;
+ margin-right: 8px;
+}
+
+.fetch-btn {
+ background: #007acc;
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ width: 100%;
+ margin-top: 10px;
+}
+
+.fetch-btn:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
+
+.fetch-btn:hover:not(:disabled) {
+ background: #005a9e;
+}
+
+.quote-display {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.price-info {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin: 10px 0;
+}
+
+.price {
+ font-size: 2rem;
+ font-weight: bold;
+ color: #333;
+}
+
+.change.positive {
+ color: #28a745;
+}
+
+.change.negative {
+ color: #dc3545;
+}
+
+.historical-summary {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ margin-top: 15px;
+}
+
+.historical-summary p {
+ margin: 5px 0;
+ font-size: 14px;
+}
+
+.analytics-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 15px;
+ margin-top: 20px;
+}
+
+.metric {
+ background: white;
+ padding: 15px;
+ border-radius: 6px;
+ border: 1px solid #e0e0e0;
+ text-align: center;
+}
+
+.metric label {
+ display: block;
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 5px;
+}
+
+.metric span {
+ font-size: 16px;
+ font-weight: bold;
+}
+
+.volatility.high, .recommendation.sell {
+ color: #dc3545;
+}
+
+.volatility.medium, .recommendation.hold {
+ color: #ffc107;
+}
+
+.volatility.low, .recommendation.buy, .trend.up {
+ color: #28a745;
+}
+
+.trend.down {
+ color: #dc3545;
+}
+
+.bulk-downloader {
+ margin-top: 30px;
+ padding: 20px;
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.download-results {
+ margin-top: 15px;
+ padding: 10px;
+ background: #d4edda;
+ border: 1px solid #c3e6cb;
+ border-radius: 4px;
+ color: #155724;
+}
+
+.admin-nav {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
+}
+
+.admin-btn {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ background: white;
+ cursor: pointer;
+ border-radius: 4px;
+}
+
+.admin-btn.active {
+ background: #007acc;
+ color: white;
+ border-color: #007acc;
+}
+
+.code-viewer {
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.code-tabs {
+ display: flex;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.code-tab {
+ padding: 12px 20px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-bottom: 3px solid transparent;
+}
+
+.code-tab.active {
+ background: #f8f9fa;
+ border-bottom-color: #007acc;
+}
+
+.code-display {
+ padding: 20px;
+}
+
+.code-block {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ overflow-x: auto;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 13px;
+ line-height: 1.4;
+ border: 1px solid #e9ecef;
+}
+
+.vendor-status {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.status-btn {
+ background: #28a745;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-bottom: 20px;
+}
+
+.status-grid {
+ display: grid;
+ gap: 15px;
+}
+
+.status-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ background: #f8f9fa;
+ border-radius: 4px;
+}
+
+.status-item label {
+ font-weight: 500;
+}
+
+.connected {
+ color: #28a745;
+}
+
+.disconnected {
+ color: #dc3545;
+}
+
+.capabilities {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.capability {
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.capability.enabled {
+ background: #d4edda;
+ color: #155724;
+}
+
+.capability.disabled {
+ background: #f8d7da;
+ color: #721c24;
+}
+
+.code-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.edit-toggle {
+ padding: 6px 12px;
+ border: 1px solid #007acc;
+ background: white;
+ color: #007acc;
+ cursor: pointer;
+ border-radius: 4px;
+ margin: 10px;
+ font-size: 12px;
+}
+
+.edit-toggle.active {
+ background: #007acc;
+ color: white;
+}
+
+.code-editor {
+ background: white;
+}
+
+.editor-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 15px;
+ border-bottom: 1px solid #e0e0e0;
+ background: #f8f9fa;
+}
+
+.editor-controls {
+ display: flex;
+ gap: 8px;
+}
+
+.history-btn, .save-btn {
+ padding: 4px 8px;
+ border: 1px solid #ddd;
+ background: white;
+ cursor: pointer;
+ border-radius: 3px;
+ font-size: 11px;
+}
+
+.save-btn {
+ background: #28a745;
+ color: white;
+ border-color: #28a745;
+}
+
+.code-textarea {
+ width: 100%;
+ min-height: 300px;
+ padding: 15px;
+ border: none;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 12px;
+ line-height: 1.4;
+ resize: vertical;
+ outline: none;
+ background: #f8f9fa;
+}
+
+.code-history {
+ background: #fff3cd;
+ padding: 10px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.history-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px 8px;
+ margin: 3px 0;
+ background: white;
+ border-radius: 3px;
+ border: 1px solid #e0e0e0;
+}
+
+.history-time {
+ font-size: 11px;
+ color: #666;
+}
+
+.revert-btn {
+ padding: 2px 6px;
+ background: #ffc107;
+ color: #212529;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ font-size: 10px;
+}
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/App.jsx b/BACKUPS/SECOND_PHASE/src/App.jsx
new file mode 100644
index 000000000..f3a1bf21a
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/App.jsx
@@ -0,0 +1,24 @@
+import React, { useEffect } from 'react';
+import './App.css';
+import TradingDashboard from './components/TradingDashboard';
+import VendorManager from './core/VendorManager';
+import ExampleVendorA from './vendors/ExampleVendorA';
+import ExampleVendorB from './vendors/ExampleVendorB';
+import YFinanceVendor from './vendors/YFinanceVendor';
+
+function App() {
+ useEffect(() => {
+ // Register vendors on app startup
+ VendorManager.registerVendor('vendorA', new ExampleVendorA());
+ VendorManager.registerVendor('vendorB', new ExampleVendorB());
+ VendorManager.registerVendor('yfinance', new YFinanceVendor());
+ }, []);
+
+ return (
+
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/App.test.jsx b/BACKUPS/SECOND_PHASE/src/App.test.jsx
new file mode 100644
index 000000000..5e9824933
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/App.test.jsx
@@ -0,0 +1,9 @@
+import { expect, test } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import App from './App';
+
+test('renders learn react link', () => {
+ render();
+ const linkElement = screen.getByText(/learn react/i);
+ expect(linkElement).toBeDefined();
+});
diff --git a/BACKUPS/SECOND_PHASE/src/components/AdminComponents.jsx b/BACKUPS/SECOND_PHASE/src/components/AdminComponents.jsx
new file mode 100644
index 000000000..953d9581b
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/components/AdminComponents.jsx
@@ -0,0 +1,323 @@
+import React, { useState } from 'react';
+import VendorManager from '../core/VendorManager';
+import { CodeEditor } from './CodeEditor';
+
+export const CodeViewer = ({ vendor }) => {
+ const [activeCode, setActiveCode] = useState('fetch');
+ const [editMode, setEditMode] = useState(false);
+ const [customCode, setCustomCode] = useState({});
+
+ const codeExamples = {
+ fetch: {
+ title: 'Data Fetching Code',
+ code: `// Market Data Fetch
+const fetchMarketData = async (symbol, interval = '1d') => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseYahooResponse(data, symbol);
+};
+
+// Historical Data Fetch
+const fetchHistoricalData = async (symbol, interval, period) => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=\${period}\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseHistoricalData(data, symbol);
+};
+
+// Bulk Download
+const bulkDownload = async (symbols, intervals, options) => {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ const data = await fetchHistoricalData(symbol, interval, options.period);
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ }
+ }
+
+ // Rate limiting
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return results;
+};`
+ },
+ parser: {
+ title: 'Data Parser Code',
+ code: `// Yahoo Response Parser
+const parseYahooResponse = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+};
+
+// Historical Data Parser
+const parseHistoricalData = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+};`
+ },
+ analytics: {
+ title: 'Analytics Code',
+ code: `// Volatility Calculator
+const calculateVolatility = (dailyData, weeklyData) => {
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+};
+
+// Recommendation Generator
+const generateRecommendation = (data) => {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+};
+
+// Analytics Fetch
+const getAnalytics = async (symbol, timeframe = '1mo') => {
+ const [daily, weekly] = await Promise.all([
+ getMarketData(symbol, '1d'),
+ getMarketData(symbol, '1wk')
+ ]);
+
+ return {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ volatility: calculateVolatility(daily.data, weekly.data),
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ recommendation: generateRecommendation(daily.data)
+ };
+};`
+ },
+ vendor: {
+ title: 'Vendor Adapter Code',
+ code: `// YFinance Vendor Class
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = \`\${symbol}_\${interval}\`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ const url = \`\${this.config.baseUrl}\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+}`
+ }
+ };
+
+ const handleCodeSave = (code) => {
+ setCustomCode(prev => ({
+ ...prev,
+ [activeCode]: code
+ }));
+ };
+
+ const getCurrentCode = () => {
+ return customCode[activeCode] || codeExamples[activeCode].code;
+ };
+
+ return (
+
+
+
+ {Object.entries(codeExamples).map(([key, example]) => (
+
+ ))}
+
+
+
+
+
+ {editMode ? (
+
+ ) : (
+
+
{codeExamples[activeCode].title}
+
+ {getCurrentCode()}
+
+
+ )}
+
+
+ );
+};
+
+export const VendorStatus = ({ vendor }) => {
+ const [status, setStatus] = useState(null);
+
+ const checkStatus = async () => {
+ try {
+ const vendorInstance = VendorManager.getVendor(vendor);
+ const capabilities = VendorManager.getVendorCapabilities(vendor);
+
+ setStatus({
+ name: vendorInstance?.name || 'Unknown',
+ connected: vendorInstance?.isConnected || false,
+ capabilities,
+ cacheSize: vendorInstance?.cache?.size || 0
+ });
+ } catch (error) {
+ setStatus({ error: error.message });
+ }
+ };
+
+ return (
+
+
+
+ {status && (
+
+ {status.error ? (
+
Error: {status.error}
+ ) : (
+
+
+
+ {status.name}
+
+
+
+
+ {status.connected ? 'Connected' : 'Disconnected'}
+
+
+
+
+ {status.cacheSize} items
+
+
+
+
+ {Object.entries(status.capabilities).map(([cap, enabled]) => (
+
+ {cap}: {enabled ? '✓' : '✗'}
+
+ ))}
+
+
+
+ )}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/components/CodeEditor.jsx b/BACKUPS/SECOND_PHASE/src/components/CodeEditor.jsx
new file mode 100644
index 000000000..c499444bf
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/components/CodeEditor.jsx
@@ -0,0 +1,75 @@
+import React, { useState, useEffect } from 'react';
+
+export const CodeEditor = ({ initialCode, title, onSave }) => {
+ const [code, setCode] = useState(initialCode);
+ const [history, setHistory] = useState([]);
+ const [showHistory, setShowHistory] = useState(false);
+
+ useEffect(() => {
+ setCode(initialCode);
+ }, [initialCode]);
+
+ const saveCode = () => {
+ const newVersion = {
+ code,
+ timestamp: new Date().toISOString(),
+ id: Date.now()
+ };
+
+ const newHistory = [newVersion, ...history].slice(0, 5);
+ setHistory(newHistory);
+
+ if (onSave) onSave(code);
+ };
+
+ const revertToVersion = (version) => {
+ setCode(version.code);
+ setShowHistory(false);
+ };
+
+ return (
+
+
+
{title}
+
+
+
+
+
+
+ {showHistory && (
+
+
Version History (Last 5)
+ {history.length === 0 ? (
+
No saved versions yet
+ ) : (
+ history.map((version) => (
+
+
+ {new Date(version.timestamp).toLocaleString()}
+
+
+
+ ))
+ )}
+
+ )}
+
+
+ );
+};
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/components/ErrorBoundary.jsx b/BACKUPS/SECOND_PHASE/src/components/ErrorBoundary.jsx
new file mode 100644
index 000000000..9028075a8
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/components/ErrorBoundary.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+class ErrorBoundary extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error, errorInfo) {
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+
Something went wrong
+
{this.props.fallbackMessage || 'This section is temporarily unavailable'}
+
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/components/TradingDashboard.jsx b/BACKUPS/SECOND_PHASE/src/components/TradingDashboard.jsx
new file mode 100644
index 000000000..8b6db8b21
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/components/TradingDashboard.jsx
@@ -0,0 +1,170 @@
+import React, { useState, useEffect } from 'react';
+import ErrorBoundary from './ErrorBoundary';
+import VendorManager from '../core/VendorManager';
+import { YFinanceMarketData, YFinanceAnalytics, YFinanceBulkDownloader } from './YFinanceComponents';
+import { CodeViewer, VendorStatus } from './AdminComponents';
+
+const TradingDashboard = () => {
+ const [activeTab, setActiveTab] = useState('market');
+ const [vendors, setVendors] = useState([]);
+ const [selectedVendor, setSelectedVendor] = useState('');
+
+ useEffect(() => {
+ setVendors(VendorManager.getAllVendors());
+ if (VendorManager.getAllVendors().length > 0) {
+ setSelectedVendor(VendorManager.getAllVendors()[0]);
+ }
+ }, []);
+
+ const tabs = [
+ { id: 'market', label: 'Market Data', capability: 'marketData' },
+ { id: 'orders', label: 'Orders', capability: 'orderManagement' },
+ { id: 'portfolio', label: 'Portfolio', capability: 'portfolio' },
+ { id: 'analytics', label: 'Analytics', capability: 'analytics' },
+ { id: 'admin', label: 'Admin', capability: 'admin' }
+ ];
+
+ const getAvailableTabs = () => {
+ if (!selectedVendor) return [];
+ const capabilities = VendorManager.getVendorCapabilities(selectedVendor);
+ return tabs.filter(tab => tab.capability === 'admin' || capabilities[tab.capability]);
+ };
+
+ const renderTabContent = () => {
+ const availableTabs = getAvailableTabs();
+ const currentTab = availableTabs.find(tab => tab.id === activeTab);
+
+ if (!currentTab) {
+ return Feature not available for selected vendor
;
+ }
+
+ switch (activeTab) {
+ case 'market':
+ return ;
+ case 'orders':
+ return ;
+ case 'portfolio':
+ return ;
+ case 'analytics':
+ return ;
+ case 'admin':
+ return ;
+ default:
+ return Select a tab
;
+ }
+ };
+
+ return (
+
+
+ Trading Dashboard
+
+
+
+
+
+
+
+ {renderTabContent()}
+
+
+
+ );
+};
+
+const MarketDataTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Market Data - Yahoo Finance
+
+
+ );
+ }
+ return (
+
+
Market Data - {vendor}
+
Market data functionality for {vendor}
+
+ );
+};
+
+const OrdersTab = ({ vendor }) => (
+
+
Order Management - {vendor}
+
Order management functionality for {vendor}
+
+);
+
+const PortfolioTab = ({ vendor }) => (
+
+
Portfolio - {vendor}
+
Portfolio functionality for {vendor}
+
+);
+
+const AnalyticsTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Analytics - Yahoo Finance
+
+
+
+ );
+ }
+ return (
+
+
Analytics - {vendor}
+
Analytics functionality for {vendor}
+
+ );
+};
+
+const AdminTab = ({ vendor }) => {
+ const [activeAdmin, setActiveAdmin] = useState('code');
+
+ return (
+
+
Admin - {vendor}
+
+
+
+
+
+ {activeAdmin === 'code' &&
}
+ {activeAdmin === 'status' &&
}
+
+ );
+};
+
+export default TradingDashboard;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/components/YFinanceComponents.jsx b/BACKUPS/SECOND_PHASE/src/components/YFinanceComponents.jsx
new file mode 100644
index 000000000..a9ece5aec
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/components/YFinanceComponents.jsx
@@ -0,0 +1,339 @@
+import React, { useState, useEffect } from 'react';
+import VendorManager from '../core/VendorManager';
+
+export const YFinanceMarketData = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [assetType, setAssetType] = useState('stocks');
+ const [interval, setInterval] = useState('1d');
+ const [period, setPeriod] = useState('1mo');
+ const [customStart, setCustomStart] = useState('');
+ const [customEnd, setCustomEnd] = useState('');
+ const [useCustomRange, setUseCustomRange] = useState(false);
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const assetTypes = {
+ stocks: { label: 'Stocks', examples: 'AAPL, GOOGL, MSFT' },
+ forex: { label: 'Forex', examples: 'EURUSD=X, GBPUSD=X, USDJPY=X' },
+ crypto: { label: 'Crypto', examples: 'BTC-USD, ETH-USD, ADA-USD' },
+ commodities: { label: 'Commodities', examples: 'GC=F, CL=F, SI=F' },
+ indices: { label: 'Indices', examples: '^GSPC, ^DJI, ^IXIC' }
+ };
+
+ const intervals = ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', '10y', 'ytd', 'max'];
+
+ const fetchData = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ setError(null);
+
+ try {
+ const fetchParams = {
+ symbol: symbol.toUpperCase(),
+ interval,
+ period: useCustomRange ? null : period,
+ start: useCustomRange ? customStart : null,
+ end: useCustomRange ? customEnd : null
+ };
+
+ const result = useCustomRange || period !== '1d'
+ ? await VendorManager.executeVendorMethod(vendor, 'getHistoricalData', fetchParams.symbol, fetchParams.interval, fetchParams.period || '1mo')
+ : await VendorManager.executeVendorMethod(vendor, 'getMarketData', fetchParams.symbol, fetchParams.interval);
+
+ if (result.success) {
+ setData(result.data);
+ } else {
+ setError(result.error);
+ }
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder={assetTypes[assetType].examples}
+ onKeyPress={(e) => e.key === 'Enter' && fetchData()}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {useCustomRange ? (
+
+ ) : (
+
+
+
+
+
+
+ )}
+
+
+
+
+ {error &&
Error: {error}
}
+
+ {data && (
+
+
{data.symbol}
+ {data.price ? (
+
+ ${data.price?.toFixed(2)}
+ = 0 ? 'positive' : 'negative'}`}>
+ {data.change >= 0 ? '+' : ''}{data.change?.toFixed(2)}
+ ({data.changePercent?.toFixed(2)}%)
+
+
+ ) : null}
+ {data.data && (
+
+
Historical data: {data.data.length} records
+
Latest: ${data.data[data.data.length - 1]?.close?.toFixed(2)}
+
+ )}
+
+ )}
+
+ );
+};
+
+export const YFinanceAnalytics = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [timeframe, setTimeframe] = useState('1mo');
+ const [analytics, setAnalytics] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const timeframes = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y'];
+
+ const fetchAnalytics = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(vendor, 'getAnalytics', symbol.toUpperCase(), timeframe);
+ if (result.success) {
+ setAnalytics(result.data);
+ }
+ } catch (err) {
+ console.error('Analytics error:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder="Enter symbol for analysis"
+ onKeyPress={(e) => e.key === 'Enter' && fetchAnalytics()}
+ />
+
+
+
+
+
+
+
+
+ {analytics && (
+
+
Analysis for {analytics.symbol} ({timeframe})
+
+
+
+ ${analytics.price?.toFixed(2)}
+
+
+
+
+ {analytics.volatility}
+
+
+
+
+
+ {analytics.weeklyTrend}
+
+
+
+
+
+ {analytics.recommendation}
+
+
+
+
+ )}
+
+ );
+};
+
+export const YFinanceBulkDownloader = ({ vendor }) => {
+ const [symbols, setSymbols] = useState('AAPL,GOOGL,MSFT');
+ const [intervals, setIntervals] = useState(['1d']);
+ const [period, setPeriod] = useState('1mo');
+ const [batchSize, setBatchSize] = useState(5);
+ const [downloading, setDownloading] = useState(false);
+ const [results, setResults] = useState(null);
+
+ const availableIntervals = ['1m', '5m', '15m', '1h', '1d', '1wk', '1mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', 'max'];
+
+ const handleBulkDownload = async () => {
+ const symbolList = symbols.split(',').map(s => s.trim().toUpperCase()).filter(s => s);
+ if (symbolList.length === 0) return;
+
+ setDownloading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(
+ vendor,
+ 'bulkDownload',
+ symbolList,
+ intervals,
+ { period, batchSize }
+ );
+ setResults(result);
+ } catch (err) {
+ console.error('Bulk download error:', err);
+ } finally {
+ setDownloading(false);
+ }
+ };
+
+ return (
+
+
Bulk Historical Data Download
+
+
+
+ setSymbols(e.target.value)}
+ placeholder="AAPL,GOOGL,MSFT,BTC-USD,EURUSD=X"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ setBatchSize(parseInt(e.target.value))}
+ min="1"
+ max="50"
+ />
+
+
+
+
+
+ {results && (
+
+
Download Complete
+
Downloaded data for {Object.keys(results.data || {}).length} symbols
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/core/BaseVendorAdapter.js b/BACKUPS/SECOND_PHASE/src/core/BaseVendorAdapter.js
new file mode 100644
index 000000000..f5f979cd7
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/core/BaseVendorAdapter.js
@@ -0,0 +1,51 @@
+export class BaseVendorAdapter {
+ constructor(name, config = {}) {
+ this.name = name;
+ this.config = config;
+ this.isConnected = false;
+ }
+
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ throw new Error('connect() must be implemented by vendor adapter');
+ }
+
+ async disconnect() {
+ this.isConnected = false;
+ }
+
+ async getMarketData(symbol) {
+ throw new Error('getMarketData() not implemented');
+ }
+
+ async placeOrder(orderData) {
+ throw new Error('placeOrder() not implemented');
+ }
+
+ async getPortfolio() {
+ throw new Error('getPortfolio() not implemented');
+ }
+
+ async getAnalytics(symbol) {
+ throw new Error('getAnalytics() not implemented');
+ }
+
+ handleError(error, context) {
+ console.error(`${this.name} Error in ${context}:`, error);
+ return {
+ success: false,
+ error: error.message,
+ vendor: this.name,
+ context
+ };
+ }
+}
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/core/VendorManager.js b/BACKUPS/SECOND_PHASE/src/core/VendorManager.js
new file mode 100644
index 000000000..b4bafabc8
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/core/VendorManager.js
@@ -0,0 +1,54 @@
+class VendorManager {
+ constructor() {
+ this.vendors = new Map();
+ this.capabilities = new Map();
+ }
+
+ registerVendor(vendorId, vendorAdapter) {
+ try {
+ if (!vendorAdapter.name || !vendorAdapter.getCapabilities) {
+ throw new Error(`Invalid vendor adapter for ${vendorId}`);
+ }
+
+ this.vendors.set(vendorId, vendorAdapter);
+ this.capabilities.set(vendorId, vendorAdapter.getCapabilities());
+ return true;
+ } catch (error) {
+ console.error(`Failed to register vendor ${vendorId}:`, error);
+ return false;
+ }
+ }
+
+ getVendor(vendorId) {
+ return this.vendors.get(vendorId);
+ }
+
+ getVendorCapabilities(vendorId) {
+ return this.capabilities.get(vendorId) || {};
+ }
+
+ getAllVendors() {
+ return Array.from(this.vendors.keys());
+ }
+
+ getVendorsWithCapability(capability) {
+ return Array.from(this.vendors.keys()).filter(vendorId =>
+ this.getVendorCapabilities(vendorId)[capability]
+ );
+ }
+
+ async executeVendorMethod(vendorId, method, ...args) {
+ try {
+ const vendor = this.getVendor(vendorId);
+ if (!vendor || !vendor[method]) {
+ throw new Error(`Method ${method} not available for vendor ${vendorId}`);
+ }
+ return await vendor[method](...args);
+ } catch (error) {
+ console.error(`Error executing ${method} for vendor ${vendorId}:`, error);
+ throw error;
+ }
+ }
+}
+
+export default new VendorManager();
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/index.css b/BACKUPS/SECOND_PHASE/src/index.css
new file mode 100644
index 000000000..ec2585e8c
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/index.css
@@ -0,0 +1,13 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
diff --git a/BACKUPS/SECOND_PHASE/src/index.jsx b/BACKUPS/SECOND_PHASE/src/index.jsx
new file mode 100644
index 000000000..d563c0fb1
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/index.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
+
+
+
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();
diff --git a/BACKUPS/SECOND_PHASE/src/logo.svg b/BACKUPS/SECOND_PHASE/src/logo.svg
new file mode 100644
index 000000000..9dfc1c058
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/reportWebVitals.js b/BACKUPS/SECOND_PHASE/src/reportWebVitals.js
new file mode 100644
index 000000000..5253d3ad9
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/reportWebVitals.js
@@ -0,0 +1,13 @@
+const reportWebVitals = onPerfEntry => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/BACKUPS/SECOND_PHASE/src/setupTests.js b/BACKUPS/SECOND_PHASE/src/setupTests.js
new file mode 100644
index 000000000..8f2609b7b
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/setupTests.js
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/BACKUPS/SECOND_PHASE/src/utils/VendorRegistry.js b/BACKUPS/SECOND_PHASE/src/utils/VendorRegistry.js
new file mode 100644
index 000000000..cb45320c8
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/utils/VendorRegistry.js
@@ -0,0 +1,56 @@
+import VendorManager from '../core/VendorManager';
+
+export const registerNewVendor = (vendorId, VendorClass, config = {}) => {
+ try {
+ const vendorInstance = new VendorClass(config);
+ const success = VendorManager.registerVendor(vendorId, vendorInstance);
+
+ if (success) {
+ console.log(`✅ Vendor ${vendorId} registered successfully`);
+ return true;
+ } else {
+ console.error(`❌ Failed to register vendor ${vendorId}`);
+ return false;
+ }
+ } catch (error) {
+ console.error(`❌ Error registering vendor ${vendorId}:`, error);
+ return false;
+ }
+};
+
+export const getVendorInfo = (vendorId) => {
+ const vendor = VendorManager.getVendor(vendorId);
+ const capabilities = VendorManager.getVendorCapabilities(vendorId);
+
+ return {
+ exists: !!vendor,
+ name: vendor?.name || 'Unknown',
+ capabilities,
+ isConnected: vendor?.isConnected || false
+ };
+};
+
+export const testVendor = async (vendorId) => {
+ try {
+ const vendor = VendorManager.getVendor(vendorId);
+ if (!vendor) {
+ return { success: false, error: 'Vendor not found' };
+ }
+
+ const connectionResult = await vendor.connect();
+ const capabilities = vendor.getCapabilities();
+
+ return {
+ success: true,
+ connection: connectionResult,
+ capabilities,
+ vendor: vendor.name
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error.message,
+ vendor: vendorId
+ };
+ }
+};
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorA.js b/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorA.js
new file mode 100644
index 000000000..46f8cdd42
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorA.js
@@ -0,0 +1,76 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorA extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor A', {
+ apiUrl: 'https://api.vendora.com',
+ apiKey: 'your-api-key'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: true,
+ portfolio: true,
+ analytics: false,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 100,
+ change: Math.random() * 10 - 5,
+ volume: Math.floor(Math.random() * 1000000)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async placeOrder(orderData) {
+ try {
+ return {
+ success: true,
+ orderId: `VA_${Date.now()}`,
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ async getPortfolio() {
+ try {
+ return {
+ success: true,
+ data: {
+ totalValue: 50000,
+ positions: [
+ { symbol: 'AAPL', quantity: 10, value: 1500 },
+ { symbol: 'GOOGL', quantity: 5, value: 12500 }
+ ]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+}
+
+export default ExampleVendorA;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorB.js b/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorB.js
new file mode 100644
index 000000000..66167fc33
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/vendors/ExampleVendorB.js
@@ -0,0 +1,66 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorB extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor B', {
+ baseUrl: 'https://vendorb-api.com/v2',
+ token: 'bearer-token'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 200,
+ bid: Math.random() * 190,
+ ask: Math.random() * 210,
+ timestamp: Date.now()
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ rsi: Math.random() * 100,
+ macd: Math.random() * 5 - 2.5,
+ sma20: Math.random() * 150,
+ sma50: Math.random() * 140,
+ recommendation: ['BUY', 'SELL', 'HOLD'][Math.floor(Math.random() * 3)]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+}
+
+export default ExampleVendorB;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/vendors/VendorTemplate.js b/BACKUPS/SECOND_PHASE/src/vendors/VendorTemplate.js
new file mode 100644
index 000000000..c411953db
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/vendors/VendorTemplate.js
@@ -0,0 +1,141 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+/**
+ * Template for creating new vendor adapters
+ * Copy this file and implement your vendor-specific logic
+ */
+class VendorTemplate extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Vendor Name', {
+ apiUrl: config.apiUrl || '',
+ apiKey: config.apiKey || '',
+ ...config
+ });
+ }
+
+ /**
+ * Define what this vendor can do
+ * Set to true only for features this vendor supports
+ */
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ /**
+ * Connect to vendor API
+ */
+ async connect() {
+ try {
+ // TODO: Implement your connection logic
+ // Example: await fetch(this.config.apiUrl + '/connect')
+
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ /**
+ * Get market data for a symbol
+ * Only implement if marketData capability is true
+ */
+ async getMarketData(symbol) {
+ try {
+ // TODO: Implement your market data API call
+ // Example:
+ // const response = await fetch(`${this.config.apiUrl}/market/${symbol}`);
+ // const data = await response.json();
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: 0,
+ change: 0,
+ volume: 0
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ /**
+ * Place an order
+ * Only implement if orderManagement capability is true
+ */
+ async placeOrder(orderData) {
+ try {
+ // TODO: Implement your order placement logic
+
+ return {
+ success: true,
+ orderId: '',
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ /**
+ * Get portfolio data
+ * Only implement if portfolio capability is true
+ */
+ async getPortfolio() {
+ try {
+ // TODO: Implement your portfolio API call
+
+ return {
+ success: true,
+ data: {
+ totalValue: 0,
+ positions: []
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+
+ /**
+ * Get analytics for a symbol
+ * Only implement if analytics capability is true
+ */
+ async getAnalytics(symbol) {
+ try {
+ // TODO: Implement your analytics API call
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ indicators: {}
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ /**
+ * Add any custom methods your vendor needs
+ */
+ async customMethod() {
+ try {
+ // Your custom implementation
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'customMethod');
+ }
+ }
+}
+
+export default VendorTemplate;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/src/vendors/YFinanceVendor.js b/BACKUPS/SECOND_PHASE/src/vendors/YFinanceVendor.js
new file mode 100644
index 000000000..963720653
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/src/vendors/YFinanceVendor.js
@@ -0,0 +1,232 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ // Test connection with a simple quote
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = `${symbol}_${interval}`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ // Use Yahoo Finance API directly (simplified version of the Python script logic)
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=1d`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ // Cache the result
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getHistoricalData(symbol, interval = '1d', period = '1mo') {
+ try {
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=${period}`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return {
+ success: true,
+ data: this.parseHistoricalData(data, symbol)
+ };
+ } catch (error) {
+ return this.handleError(error, 'getHistoricalData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ // Get multiple timeframes for analytics
+ const [daily, weekly] = await Promise.all([
+ this.getMarketData(symbol, '1d'),
+ this.getMarketData(symbol, '1wk')
+ ]);
+
+ if (!daily.success || !weekly.success) {
+ throw new Error('Failed to fetch data for analytics');
+ }
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ marketCap: daily.data.marketCap,
+ pe: daily.data.pe,
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ volatility: this.calculateVolatility(daily.data, weekly.data),
+ recommendation: this.generateRecommendation(daily.data)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ parseYahooResponse(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid response format');
+ }
+
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ marketCap: meta.marketCap || null,
+ pe: meta.trailingPE || null,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse Yahoo response: ${error.message}`);
+ }
+ }
+
+ parseHistoricalData(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid historical data format');
+ }
+
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse historical data: ${error.message}`);
+ }
+ }
+
+ calculateVolatility(dailyData, weeklyData) {
+ // Simple volatility calculation
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+ }
+
+ generateRecommendation(data) {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+ }
+
+ // Bulk download method (adapted from Python script)
+ async bulkDownload(symbols, intervals = ['1d'], options = {}) {
+ try {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ try {
+ const data = await this.getHistoricalData(symbol, interval, options.period || '1mo');
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ } catch (error) {
+ console.warn(`Failed to download ${symbol} ${interval}:`, error);
+ }
+ }
+ }
+
+ // Rate limiting (like the Python script)
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return { success: true, data: results };
+ } catch (error) {
+ return this.handleError(error, 'bulkDownload');
+ }
+ }
+}
+
+export default YFinanceVendor;
\ No newline at end of file
diff --git a/BACKUPS/SECOND_PHASE/vite.config.js b/BACKUPS/SECOND_PHASE/vite.config.js
new file mode 100644
index 000000000..248c2f847
--- /dev/null
+++ b/BACKUPS/SECOND_PHASE/vite.config.js
@@ -0,0 +1,11 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ globals: true,
+ environment: 'jsdom',
+ },
+})
diff --git a/BACKUPS/restore_phases.md b/BACKUPS/restore_phases.md
new file mode 100644
index 000000000..d30dfb46d
--- /dev/null
+++ b/BACKUPS/restore_phases.md
@@ -0,0 +1,25 @@
+# PHASE RESTORATION GUIDE
+
+## Available Phases:
+
+### FIRST PHASE
+- Basic Trading Dashboard
+- YFinance Integration
+- Read-only Code Viewer
+- **Restore:** `cp -r BACKUPS/FIRST_PHASE/src/ ./`
+
+### SECOND PHASE
+- All First Phase features
+- Code Editor with Version History
+- Edit/View Toggle
+- **Restore:** `cp -r BACKUPS/SECOND_PHASE/src/ ./`
+
+## Quick Restore Commands:
+
+```bash
+# Restore First Phase (Basic)
+rm -rf src/ && cp -r BACKUPS/FIRST_PHASE/src/ ./
+
+# Restore Second Phase (With Editor)
+rm -rf src/ && cp -r BACKUPS/SECOND_PHASE/src/ ./
+```
\ No newline at end of file
diff --git a/README_VENDOR_INTEGRATION.md b/README_VENDOR_INTEGRATION.md
new file mode 100644
index 000000000..fbaf7dd59
--- /dev/null
+++ b/README_VENDOR_INTEGRATION.md
@@ -0,0 +1,81 @@
+# Vendor Integration Guide
+
+## Adding New Vendors
+
+### 1. Create Vendor Adapter
+
+Create a new file in `src/vendors/YourVendor.js`:
+
+```javascript
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class YourVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Your Vendor Name', config);
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true, // Can fetch market data
+ orderManagement: false, // Cannot place orders
+ portfolio: true, // Can get portfolio data
+ analytics: false, // No analytics
+ realtime: true // Supports real-time data
+ };
+ }
+
+ async connect() {
+ // Your connection logic
+ this.isConnected = true;
+ return { success: true };
+ }
+
+ async getMarketData(symbol) {
+ // Your market data implementation
+ return {
+ success: true,
+ data: { symbol, price: 100, change: 5 }
+ };
+ }
+
+ // Implement other methods as needed
+}
+
+export default YourVendor;
+```
+
+### 2. Register Vendor
+
+In `src/App.jsx`, add your vendor:
+
+```javascript
+import YourVendor from './vendors/YourVendor';
+
+// In useEffect
+VendorManager.registerVendor('yourVendorId', new YourVendor());
+```
+
+### 3. Vendor Capabilities
+
+The UI automatically adapts based on vendor capabilities:
+- Tabs only show if vendor supports the feature
+- Error boundaries prevent crashes
+- Graceful fallbacks for missing features
+
+### 4. API Integration
+
+Each vendor can have completely different:
+- API endpoints
+- Authentication methods
+- Data formats
+- Available features
+
+The BaseVendorAdapter provides error handling and standardized interface.
+
+## Architecture Benefits
+
+- **Fault Isolation**: Vendor failures don't crash the UI
+- **Dynamic Capabilities**: UI adapts to vendor features
+- **Easy Extension**: Add vendors without changing core UI
+- **Consistent Interface**: All vendors use same base methods
+- **Error Recovery**: Built-in retry mechanisms
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index c8f61bf33..5bb23f603 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,15 +11,16 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
+ "jszip": "^3.10.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"web-vitals": "^3.1.0"
},
"devDependencies": {
- "@vitejs/plugin-react": "^6.0.1",
+ "@vitejs/plugin-react": "^4.7.0",
"jsdom": "^26.1.0",
- "vite": "^8.0.16",
- "vitest": "^4.1.6"
+ "vite": "^6.3.6",
+ "vitest": "^3.0.7"
}
},
"node_modules/@adobe/css-tools": {
@@ -27,6 +28,20 @@
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
},
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@asamuzakjp/css-color": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
@@ -62,6 +77,143 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
+ "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
+ "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.27.3",
+ "@babel/helpers": "^7.27.6",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
+ "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.27.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
+ "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.27.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-validator-identifier": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
@@ -71,6 +223,78 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.27.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
+ "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.27.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
+ "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
@@ -82,6 +306,54 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
+ "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.1",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz",
+ "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@csstools/color-helpers": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
@@ -197,35 +469,429 @@
"node": ">=18"
}
},
- "node_modules/@emnapi/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
- "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+ "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+ "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+ "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+ "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+ "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+ "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+ "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+ "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+ "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+ "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+ "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+ "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+ "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+ "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+ "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+ "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+ "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+ "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
+ "license": "MIT",
"optional": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.2.1",
- "tslib": "^2.4.0"
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@emnapi/runtime": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+ "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
+ "cpu": [
+ "ia32"
+ ],
"dev": true,
+ "license": "MIT",
"optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/@emnapi/wasi-threads": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+ "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "license": "MIT",
"optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@jest/expect-utils": {
@@ -277,8 +943,6 @@
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
"dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -289,8 +953,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"dev": true,
- "optional": true,
- "peer": true,
"engines": {
"node": ">=6.0.0"
}
@@ -308,10 +970,11 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
- "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
+ "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.29",
@@ -319,44 +982,35 @@
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
"dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
- "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
"dev": true,
- "optional": true,
- "dependencies": {
- "@tybys/wasm-util": "^0.10.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Brooooooklyn"
- },
- "peerDependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1"
- }
+ "license": "MIT"
},
- "node_modules/@oxc-project/types": {
- "version": "0.133.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
- "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz",
+ "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==",
+ "cpu": [
+ "arm"
+ ],
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/Boshen"
- }
+ "optional": true,
+ "os": [
+ "android"
+ ]
},
- "node_modules/@rolldown/binding-android-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
- "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz",
+ "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==",
"cpu": [
"arm64"
],
@@ -364,15 +1018,12 @@
"optional": true,
"os": [
"android"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-darwin-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
- "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz",
+ "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==",
"cpu": [
"arm64"
],
@@ -380,15 +1031,12 @@
"optional": true,
"os": [
"darwin"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-darwin-x64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
- "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz",
+ "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==",
"cpu": [
"x64"
],
@@ -396,15 +1044,25 @@
"optional": true,
"os": [
"darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz",
+ "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==",
+ "cpu": [
+ "arm64"
],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
},
- "node_modules/@rolldown/binding-freebsd-x64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
- "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz",
+ "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==",
"cpu": [
"x64"
],
@@ -412,15 +1070,12 @@
"optional": true,
"os": [
"freebsd"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
- "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz",
+ "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==",
"cpu": [
"arm"
],
@@ -428,15 +1083,25 @@
"optional": true,
"os": [
"linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz",
+ "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==",
+ "cpu": [
+ "arm"
],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
},
- "node_modules/@rolldown/binding-linux-arm64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
- "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz",
+ "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==",
"cpu": [
"arm64"
],
@@ -444,15 +1109,12 @@
"optional": true,
"os": [
"linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-linux-arm64-musl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
- "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz",
+ "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==",
"cpu": [
"arm64"
],
@@ -460,15 +1122,25 @@
"optional": true,
"os": [
"linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz",
+ "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==",
+ "cpu": [
+ "loong64"
],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
},
- "node_modules/@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
- "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz",
+ "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==",
"cpu": [
"ppc64"
],
@@ -476,15 +1148,38 @@
"optional": true,
"os": [
"linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz",
+ "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz",
+ "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==",
+ "cpu": [
+ "riscv64"
],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
},
- "node_modules/@rolldown/binding-linux-s390x-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
- "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz",
+ "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==",
"cpu": [
"s390x"
],
@@ -492,15 +1187,12 @@
"optional": true,
"os": [
"linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-linux-x64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
- "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz",
+ "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==",
"cpu": [
"x64"
],
@@ -508,15 +1200,12 @@
"optional": true,
"os": [
"linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-linux-x64-musl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
- "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz",
+ "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==",
"cpu": [
"x64"
],
@@ -524,15 +1213,12 @@
"optional": true,
"os": [
"linux"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-openharmony-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
- "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz",
+ "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==",
"cpu": [
"arm64"
],
@@ -540,49 +1226,38 @@
"optional": true,
"os": [
"openharmony"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-wasm32-wasi": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
- "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz",
+ "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==",
"cpu": [
- "wasm32"
+ "arm64"
],
"dev": true,
"optional": true,
- "dependencies": {
- "@emnapi/core": "1.10.0",
- "@emnapi/runtime": "1.10.0",
- "@napi-rs/wasm-runtime": "^1.1.4"
- },
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ "os": [
+ "win32"
+ ]
},
- "node_modules/@rolldown/binding-win32-arm64-msvc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
- "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz",
+ "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==",
"cpu": [
- "arm64"
+ "ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
+ ]
},
- "node_modules/@rolldown/binding-win32-x64-msvc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
- "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz",
+ "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==",
"cpu": [
"x64"
],
@@ -590,22 +1265,7 @@
"optional": true,
"os": [
"win32"
- ],
- "engines": {
- "node": "^20.19.0 || >=22.12.0"
- }
- },
- "node_modules/@rolldown/pluginutils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
- "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
- "dev": true
- },
- "node_modules/@standard-schema/spec": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
- "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
- "dev": true
+ ]
},
"node_modules/@testing-library/dom": {
"version": "8.19.1",
@@ -687,36 +1347,55 @@
"@testing-library/dom": ">=7.21.4"
}
},
- "node_modules/@tybys/wasm-util": {
- "version": "0.10.2",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
- "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
"node_modules/@types/aria-query": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz",
"integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q=="
},
- "node_modules/@types/chai": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
- "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@types/deep-eql": "*",
- "assertion-error": "^2.0.1"
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
}
},
- "node_modules/@types/deep-eql": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
- "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
- "dev": true
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
+ "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.20.7"
+ }
},
"node_modules/@types/estree": {
"version": "1.0.8",
@@ -784,12 +1463,9 @@
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@types/node": {
- "version": "25.7.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz",
- "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
- "dependencies": {
- "undici-types": "~7.21.0"
- }
+ "version": "18.11.18",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
+ "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
@@ -846,69 +1522,57 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
},
"node_modules/@vitejs/plugin-react": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz",
- "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@rolldown/pluginutils": "1.0.0-rc.7"
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
},
"engines": {
- "node": "^20.19.0 || >=22.12.0"
+ "node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
- "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
- "babel-plugin-react-compiler": "^1.0.0",
- "vite": "^8.0.0"
- },
- "peerDependenciesMeta": {
- "@rolldown/plugin-babel": {
- "optional": true
- },
- "babel-plugin-react-compiler": {
- "optional": true
- }
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
- "node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-rc.7",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz",
- "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==",
- "dev": true
- },
"node_modules/@vitest/expect": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
- "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.7.tgz",
+ "integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==",
"dev": true,
"dependencies": {
- "@standard-schema/spec": "^1.1.0",
- "@types/chai": "^5.2.2",
- "@vitest/spy": "4.1.6",
- "@vitest/utils": "4.1.6",
- "chai": "^6.2.2",
- "tinyrainbow": "^3.1.0"
+ "@vitest/spy": "3.0.7",
+ "@vitest/utils": "3.0.7",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/mocker": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz",
- "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.7.tgz",
+ "integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dev": true,
"dependencies": {
- "@vitest/spy": "4.1.6",
+ "@vitest/spy": "3.0.7",
"estree-walker": "^3.0.3",
- "magic-string": "^0.30.21"
+ "magic-string": "^0.30.17"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "vite": "^5.0.0 || ^6.0.0"
},
"peerDependenciesMeta": {
"msw": {
@@ -920,24 +1584,24 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz",
- "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.7.tgz",
+ "integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==",
"dev": true,
"dependencies": {
- "tinyrainbow": "^3.1.0"
+ "tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/runner": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz",
- "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.7.tgz",
+ "integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==",
"dev": true,
"dependencies": {
- "@vitest/utils": "4.1.6",
+ "@vitest/utils": "3.0.7",
"pathe": "^2.0.3"
},
"funding": {
@@ -945,14 +1609,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz",
- "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.7.tgz",
+ "integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==",
"dev": true,
"dependencies": {
- "@vitest/pretty-format": "4.1.6",
- "@vitest/utils": "4.1.6",
- "magic-string": "^0.30.21",
+ "@vitest/pretty-format": "3.0.7",
+ "magic-string": "^0.30.17",
"pathe": "^2.0.3"
},
"funding": {
@@ -960,23 +1623,26 @@
}
},
"node_modules/@vitest/spy": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz",
- "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.7.tgz",
+ "integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==",
"dev": true,
+ "dependencies": {
+ "tinyspy": "^3.0.2"
+ },
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/utils": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz",
- "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.7.tgz",
+ "integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==",
"dev": true,
"dependencies": {
- "@vitest/pretty-format": "4.1.6",
- "convert-source-map": "^2.0.0",
- "tinyrainbow": "^3.1.0"
+ "@vitest/pretty-format": "3.0.7",
+ "loupe": "^3.1.3",
+ "tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
@@ -1067,6 +1733,39 @@
"node": ">=8"
}
},
+ "node_modules/browserslist": {
+ "version": "4.25.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
+ "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001726",
+ "electron-to-chromium": "^1.5.173",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -1075,6 +1774,15 @@
"optional": true,
"peer": true
},
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -1087,13 +1795,41 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001727",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
+ "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
"node_modules/chai": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
- "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+ "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
"dev": true,
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
"engines": {
- "node": ">=18"
+ "node": ">=12"
}
},
"node_modules/chalk": {
@@ -1111,6 +1847,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/check-error": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+ "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 16"
+ }
+ },
"node_modules/ci-info": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz",
@@ -1148,6 +1893,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"node_modules/css.escape": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -1210,6 +1960,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/deep-equal": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz",
@@ -1252,15 +2011,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/detect-libc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -1274,6 +2024,13 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz",
"integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw=="
},
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.189",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.189.tgz",
+ "integrity": "sha512-y9D1ntS1ruO/pZ/V2FtLE+JXLQe28XoRpZ7QCCo0T8LdQladzdcOVQZH/IWLVJvCw12OGMb6hYOeOAjntCmJRQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
@@ -1306,11 +2063,62 @@
}
},
"node_modules/es-module-lexer": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
- "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+ "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
"dev": true
},
+ "node_modules/esbuild": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+ "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.0",
+ "@esbuild/android-arm": "0.25.0",
+ "@esbuild/android-arm64": "0.25.0",
+ "@esbuild/android-x64": "0.25.0",
+ "@esbuild/darwin-arm64": "0.25.0",
+ "@esbuild/darwin-x64": "0.25.0",
+ "@esbuild/freebsd-arm64": "0.25.0",
+ "@esbuild/freebsd-x64": "0.25.0",
+ "@esbuild/linux-arm": "0.25.0",
+ "@esbuild/linux-arm64": "0.25.0",
+ "@esbuild/linux-ia32": "0.25.0",
+ "@esbuild/linux-loong64": "0.25.0",
+ "@esbuild/linux-mips64el": "0.25.0",
+ "@esbuild/linux-ppc64": "0.25.0",
+ "@esbuild/linux-riscv64": "0.25.0",
+ "@esbuild/linux-s390x": "0.25.0",
+ "@esbuild/linux-x64": "0.25.0",
+ "@esbuild/netbsd-arm64": "0.25.0",
+ "@esbuild/netbsd-x64": "0.25.0",
+ "@esbuild/openbsd-arm64": "0.25.0",
+ "@esbuild/openbsd-x64": "0.25.0",
+ "@esbuild/sunos-x64": "0.25.0",
+ "@esbuild/win32-arm64": "0.25.0",
+ "@esbuild/win32-ia32": "0.25.0",
+ "@esbuild/win32-x64": "0.25.0"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
@@ -1336,9 +2144,9 @@
}
},
"node_modules/expect-type": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
- "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz",
+ "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==",
"dev": true,
"engines": {
"node": ">=12.0.0"
@@ -1390,6 +2198,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -1536,6 +2354,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -1544,6 +2367,11 @@
"node": ">=8"
}
},
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -1967,259 +2795,55 @@
}
}
},
- "node_modules/lightningcss": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
- "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
- "dev": true,
- "dependencies": {
- "detect-libc": "^2.0.3"
- },
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- },
- "optionalDependencies": {
- "lightningcss-android-arm64": "1.32.0",
- "lightningcss-darwin-arm64": "1.32.0",
- "lightningcss-darwin-x64": "1.32.0",
- "lightningcss-freebsd-x64": "1.32.0",
- "lightningcss-linux-arm-gnueabihf": "1.32.0",
- "lightningcss-linux-arm64-gnu": "1.32.0",
- "lightningcss-linux-arm64-musl": "1.32.0",
- "lightningcss-linux-x64-gnu": "1.32.0",
- "lightningcss-linux-x64-musl": "1.32.0",
- "lightningcss-win32-arm64-msvc": "1.32.0",
- "lightningcss-win32-x64-msvc": "1.32.0"
- }
- },
- "node_modules/lightningcss-android-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
- "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-darwin-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
- "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-darwin-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
- "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-freebsd-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
- "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm-gnueabihf": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
- "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
- "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-arm64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
- "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "node": ">=6"
}
},
- "node_modules/lightningcss-linux-x64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
- "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
- "cpu": [
- "x64"
- ],
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 12.0.0"
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
- }
- },
- "node_modules/lightningcss-linux-x64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
- "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "node": ">=6"
}
},
- "node_modules/lightningcss-win32-arm64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
- "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
}
},
- "node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
- "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 12.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/parcel"
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "dependencies": {
+ "immediate": "~3.0.5"
}
},
"node_modules/lodash": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
- "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
@@ -2232,6 +2856,22 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/loupe": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
+ "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
"node_modules/lz-string": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
@@ -2241,12 +2881,12 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.21",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
- "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.5"
+ "@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/micromatch": {
@@ -2276,9 +2916,9 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.3.16",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
- "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"funding": [
{
@@ -2293,6 +2933,13 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/nwsapi": {
"version": "2.2.20",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
@@ -2348,15 +2995,10 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/obug": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
- "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
- "dev": true,
- "funding": [
- "https://github.com/sponsors/sxzz",
- "https://opencollective.com/debug"
- ]
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/parse5": {
"version": "7.3.0",
@@ -2377,6 +3019,15 @@
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
+ "node_modules/pathval": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+ "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -2384,9 +3035,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
- "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"engines": {
"node": ">=8.6"
},
@@ -2395,9 +3046,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.25",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
- "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@@ -2414,9 +3065,9 @@
}
],
"dependencies": {
- "nanoid": "^3.3.16",
- "picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -2446,6 +3097,11 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -2479,10 +3135,39 @@
"react": "^18.2.0"
}
},
- "node_modules/react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ "node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/redent": {
"version": "3.0.0",
@@ -2517,37 +3202,44 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/rolldown": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
- "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
+ "node_modules/rollup": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
+ "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
"dev": true,
"dependencies": {
- "@oxc-project/types": "=0.133.0",
- "@rolldown/pluginutils": "^1.0.0"
+ "@types/estree": "1.0.8"
},
"bin": {
- "rolldown": "bin/cli.mjs"
+ "rollup": "dist/bin/rollup"
},
"engines": {
- "node": "^20.19.0 || >=22.12.0"
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rolldown/binding-android-arm64": "1.0.3",
- "@rolldown/binding-darwin-arm64": "1.0.3",
- "@rolldown/binding-darwin-x64": "1.0.3",
- "@rolldown/binding-freebsd-x64": "1.0.3",
- "@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
- "@rolldown/binding-linux-arm64-gnu": "1.0.3",
- "@rolldown/binding-linux-arm64-musl": "1.0.3",
- "@rolldown/binding-linux-ppc64-gnu": "1.0.3",
- "@rolldown/binding-linux-s390x-gnu": "1.0.3",
- "@rolldown/binding-linux-x64-gnu": "1.0.3",
- "@rolldown/binding-linux-x64-musl": "1.0.3",
- "@rolldown/binding-openharmony-arm64": "1.0.3",
- "@rolldown/binding-wasm32-wasi": "1.0.3",
- "@rolldown/binding-win32-arm64-msvc": "1.0.3",
- "@rolldown/binding-win32-x64-msvc": "1.0.3"
+ "@rollup/rollup-android-arm-eabi": "4.50.1",
+ "@rollup/rollup-android-arm64": "4.50.1",
+ "@rollup/rollup-darwin-arm64": "4.50.1",
+ "@rollup/rollup-darwin-x64": "4.50.1",
+ "@rollup/rollup-freebsd-arm64": "4.50.1",
+ "@rollup/rollup-freebsd-x64": "4.50.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.50.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.50.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.50.1",
+ "@rollup/rollup-linux-arm64-musl": "4.50.1",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.50.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.50.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.50.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.50.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.50.1",
+ "@rollup/rollup-linux-x64-gnu": "4.50.1",
+ "@rollup/rollup-linux-x64-musl": "4.50.1",
+ "@rollup/rollup-openharmony-arm64": "4.50.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.50.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.50.1",
+ "@rollup/rollup-win32-x64-msvc": "4.50.1",
+ "fsevents": "~2.3.2"
}
},
"node_modules/rrweb-cssom": {
@@ -2557,6 +3249,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -2584,6 +3281,21 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -2612,9 +3324,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -2669,11 +3381,19 @@
"dev": true
},
"node_modules/std-env": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
- "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz",
+ "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==",
"dev": true
},
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -2737,22 +3457,19 @@
"dev": true
},
"node_modules/tinyexec": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz",
- "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==",
- "dev": true,
- "engines": {
- "node": ">=18"
- }
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+ "dev": true
},
"node_modules/tinyglobby": {
- "version": "0.2.17",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
- "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"dependencies": {
"fdir": "^6.5.0",
- "picomatch": "^4.0.4"
+ "picomatch": "^4.0.3"
},
"engines": {
"node": ">=12.0.0"
@@ -2779,9 +3496,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"engines": {
"node": ">=12"
@@ -2790,10 +3507,28 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/tinypool": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+ "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+ "dev": true,
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
"node_modules/tinyrainbow": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
- "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
"dev": true,
"engines": {
"node": ">=14.0.0"
@@ -2856,35 +3591,60 @@
"node": ">=18"
}
},
- "node_modules/tslib": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true,
- "optional": true
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
},
- "node_modules/undici-types": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz",
- "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ=="
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": {
- "version": "8.0.16",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
- "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+ "version": "6.3.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
+ "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
"dev": true,
"dependencies": {
- "lightningcss": "^1.32.0",
- "picomatch": "^4.0.4",
- "postcss": "^8.5.15",
- "rolldown": "1.0.3",
- "tinyglobby": "^0.2.17"
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^20.19.0 || >=22.12.0"
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -2893,15 +3653,14 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^20.19.0 || >=22.12.0",
- "@vitejs/devtools": "^0.1.18",
- "esbuild": "^0.27.0 || ^0.28.0",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
"jiti": ">=1.21.0",
- "less": "^4.0.0",
- "sass": "^1.70.0",
- "sass-embedded": "^1.70.0",
- "stylus": ">=0.54.8",
- "sugarss": "^5.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
"terser": "^5.16.0",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
@@ -2910,18 +3669,15 @@
"@types/node": {
"optional": true
},
- "@vitejs/devtools": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- },
"jiti": {
"optional": true
},
"less": {
"optional": true
},
+ "lightningcss": {
+ "optional": true
+ },
"sass": {
"optional": true
},
@@ -2945,10 +3701,49 @@
}
}
},
+ "node_modules/vite-node": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.7.tgz",
+ "integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==",
+ "dev": true,
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.0",
+ "es-module-lexer": "^1.6.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vite/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vite/node_modules/picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"engines": {
"node": ">=12"
@@ -2958,78 +3753,61 @@
}
},
"node_modules/vitest": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz",
- "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==",
- "dev": true,
- "dependencies": {
- "@vitest/expect": "4.1.6",
- "@vitest/mocker": "4.1.6",
- "@vitest/pretty-format": "4.1.6",
- "@vitest/runner": "4.1.6",
- "@vitest/snapshot": "4.1.6",
- "@vitest/spy": "4.1.6",
- "@vitest/utils": "4.1.6",
- "es-module-lexer": "^2.0.0",
- "expect-type": "^1.3.0",
- "magic-string": "^0.30.21",
- "obug": "^2.1.1",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.7.tgz",
+ "integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==",
+ "dev": true,
+ "dependencies": {
+ "@vitest/expect": "3.0.7",
+ "@vitest/mocker": "3.0.7",
+ "@vitest/pretty-format": "^3.0.7",
+ "@vitest/runner": "3.0.7",
+ "@vitest/snapshot": "3.0.7",
+ "@vitest/spy": "3.0.7",
+ "@vitest/utils": "3.0.7",
+ "chai": "^5.2.0",
+ "debug": "^4.4.0",
+ "expect-type": "^1.1.0",
+ "magic-string": "^0.30.17",
"pathe": "^2.0.3",
- "picomatch": "^4.0.3",
- "std-env": "^4.0.0-rc.1",
+ "std-env": "^3.8.0",
"tinybench": "^2.9.0",
- "tinyexec": "^1.0.2",
- "tinyglobby": "^0.2.15",
- "tinyrainbow": "^3.1.0",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "tinyexec": "^0.3.2",
+ "tinypool": "^1.0.2",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0",
+ "vite-node": "3.0.7",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
- "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
- "@opentelemetry/api": "^1.9.0",
- "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "@vitest/browser-playwright": "4.1.6",
- "@vitest/browser-preview": "4.1.6",
- "@vitest/browser-webdriverio": "4.1.6",
- "@vitest/coverage-istanbul": "4.1.6",
- "@vitest/coverage-v8": "4.1.6",
- "@vitest/ui": "4.1.6",
+ "@types/debug": "^4.1.12",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@vitest/browser": "3.0.7",
+ "@vitest/ui": "3.0.7",
"happy-dom": "*",
- "jsdom": "*",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "jsdom": "*"
},
"peerDependenciesMeta": {
"@edge-runtime/vm": {
"optional": true
},
- "@opentelemetry/api": {
+ "@types/debug": {
"optional": true
},
"@types/node": {
"optional": true
},
- "@vitest/browser-playwright": {
- "optional": true
- },
- "@vitest/browser-preview": {
- "optional": true
- },
- "@vitest/browser-webdriverio": {
- "optional": true
- },
- "@vitest/coverage-istanbul": {
- "optional": true
- },
- "@vitest/coverage-v8": {
+ "@vitest/browser": {
"optional": true
},
"@vitest/ui": {
@@ -3040,24 +3818,9 @@
},
"jsdom": {
"optional": true
- },
- "vite": {
- "optional": false
}
}
},
- "node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/w3c-xmlserializer": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
@@ -3188,10 +3951,11 @@
}
},
"node_modules/ws": {
- "version": "8.21.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
- "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10.0.0"
},
@@ -3223,6 +3987,13 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
}
},
"dependencies": {
@@ -3231,6 +4002,16 @@
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
"integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw=="
},
+ "@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
"@asamuzakjp/css-color": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
@@ -3262,11 +4043,148 @@
"picocolors": "^1.1.1"
}
},
+ "@babel/compat-data": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
+ "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
+ "dev": true
+ },
+ "@babel/core": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
+ "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
+ "dev": true,
+ "requires": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.27.3",
+ "@babel/helpers": "^7.27.6",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ }
+ },
+ "@babel/generator": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
+ "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ }
+ },
+ "@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "requires": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ }
+ },
+ "@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "dev": true,
+ "requires": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.27.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
+ "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.27.3"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "dev": true
+ },
+ "@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true
+ },
"@babel/helper-validator-identifier": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="
},
+ "@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true
+ },
+ "@babel/helpers": {
+ "version": "7.27.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
+ "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.27.6"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
+ "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.28.0"
+ }
+ },
+ "@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ }
+ },
+ "@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ }
+ },
"@babel/runtime": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
@@ -3275,6 +4193,42 @@
"regenerator-runtime": "^0.14.0"
}
},
+ "@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
+ "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.0",
+ "debug": "^4.3.1"
+ }
+ },
+ "@babel/types": {
+ "version": "7.28.1",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz",
+ "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ }
+ },
"@csstools/color-helpers": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
@@ -3303,44 +4257,188 @@
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
"dev": true,
- "requires": {}
+ "requires": {}
+ },
+ "@csstools/css-tokenizer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+ "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
+ "dev": true
+ },
+ "@esbuild/aix-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+ "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+ "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+ "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/android-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+ "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+ "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/darwin-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+ "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/freebsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+ "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+ "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+ "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+ "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-loong64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+ "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-mips64el": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+ "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+ "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-riscv64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+ "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-s390x": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+ "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/linux-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+ "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/netbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/netbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
+ "dev": true,
+ "optional": true
+ },
+ "@esbuild/openbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
+ "dev": true,
+ "optional": true
},
- "@csstools/css-tokenizer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
- "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
- "dev": true
+ "@esbuild/openbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
+ "dev": true,
+ "optional": true
},
- "@emnapi/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
- "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "@esbuild/sunos-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+ "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
"dev": true,
- "optional": true,
- "requires": {
- "@emnapi/wasi-threads": "1.2.1",
- "tslib": "^2.4.0"
- }
+ "optional": true
},
- "@emnapi/runtime": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "@esbuild/win32-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+ "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
"dev": true,
- "optional": true,
- "requires": {
- "tslib": "^2.4.0"
- }
+ "optional": true
},
- "@emnapi/wasi-threads": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "@esbuild/win32-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+ "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
"dev": true,
- "optional": true,
- "requires": {
- "tslib": "^2.4.0"
- }
+ "optional": true
+ },
+ "@esbuild/win32-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+ "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
+ "dev": true,
+ "optional": true
},
"@jest/expect-utils": {
"version": "29.3.1",
@@ -3383,8 +4481,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
"dev": true,
- "optional": true,
- "peer": true,
"requires": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -3394,9 +4490,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true,
- "optional": true,
- "peer": true
+ "dev": true
},
"@jridgewell/source-map": {
"version": "0.3.2",
@@ -3411,9 +4505,9 @@
}
},
"@jridgewell/sourcemap-codec": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
- "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
+ "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
"dev": true
},
"@jridgewell/trace-mapping": {
@@ -3421,150 +4515,163 @@
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
"dev": true,
- "optional": true,
- "peer": true,
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "@napi-rs/wasm-runtime": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
- "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
+ "@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true
+ },
+ "@rollup/rollup-android-arm-eabi": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz",
+ "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==",
"dev": true,
- "optional": true,
- "requires": {
- "@tybys/wasm-util": "^0.10.2"
- }
+ "optional": true
},
- "@oxc-project/types": {
- "version": "0.133.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
- "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
- "dev": true
+ "@rollup/rollup-android-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz",
+ "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==",
+ "dev": true,
+ "optional": true
},
- "@rolldown/binding-android-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
- "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
+ "@rollup/rollup-darwin-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz",
+ "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==",
"dev": true,
"optional": true
},
- "@rolldown/binding-darwin-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
- "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
+ "@rollup/rollup-darwin-x64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz",
+ "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==",
"dev": true,
"optional": true
},
- "@rolldown/binding-darwin-x64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
- "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
+ "@rollup/rollup-freebsd-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz",
+ "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==",
"dev": true,
"optional": true
},
- "@rolldown/binding-freebsd-x64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
- "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
+ "@rollup/rollup-freebsd-x64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz",
+ "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
- "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
+ "@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz",
+ "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-arm64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
- "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
+ "@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz",
+ "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-arm64-musl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
- "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
+ "@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz",
+ "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
- "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
+ "@rollup/rollup-linux-arm64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz",
+ "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-s390x-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
- "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
+ "@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz",
+ "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-x64-gnu": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
- "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
+ "@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz",
+ "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==",
"dev": true,
"optional": true
},
- "@rolldown/binding-linux-x64-musl": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
- "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
+ "@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz",
+ "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==",
"dev": true,
"optional": true
},
- "@rolldown/binding-openharmony-arm64": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
- "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
+ "@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz",
+ "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==",
"dev": true,
"optional": true
},
- "@rolldown/binding-wasm32-wasi": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
- "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
+ "@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz",
+ "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==",
"dev": true,
- "optional": true,
- "requires": {
- "@emnapi/core": "1.10.0",
- "@emnapi/runtime": "1.10.0",
- "@napi-rs/wasm-runtime": "^1.1.4"
- }
+ "optional": true
},
- "@rolldown/binding-win32-arm64-msvc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
- "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
+ "@rollup/rollup-linux-x64-gnu": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz",
+ "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==",
"dev": true,
"optional": true
},
- "@rolldown/binding-win32-x64-msvc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
- "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
+ "@rollup/rollup-linux-x64-musl": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz",
+ "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==",
"dev": true,
"optional": true
},
- "@rolldown/pluginutils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
- "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
- "dev": true
+ "@rollup/rollup-openharmony-arm64": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz",
+ "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==",
+ "dev": true,
+ "optional": true
},
- "@standard-schema/spec": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
- "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
- "dev": true
+ "@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz",
+ "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz",
+ "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==",
+ "dev": true,
+ "optional": true
+ },
+ "@rollup/rollup-win32-x64-msvc": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz",
+ "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==",
+ "dev": true,
+ "optional": true
},
"@testing-library/dom": {
"version": "8.19.1",
@@ -3624,36 +4731,51 @@
"integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==",
"requires": {}
},
- "@tybys/wasm-util": {
- "version": "0.10.2",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
- "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
- "dev": true,
- "optional": true,
- "requires": {
- "tslib": "^2.4.0"
- }
- },
"@types/aria-query": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz",
"integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q=="
},
- "@types/chai": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
- "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+ "@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"dev": true,
"requires": {
- "@types/deep-eql": "*",
- "assertion-error": "^2.0.1"
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
}
},
- "@types/deep-eql": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
- "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
- "dev": true
+ "@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__traverse": {
+ "version": "7.20.7",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
+ "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.20.7"
+ }
},
"@types/estree": {
"version": "1.0.8",
@@ -3714,12 +4836,9 @@
}
},
"@types/node": {
- "version": "25.7.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz",
- "integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
- "requires": {
- "undici-types": "~7.21.0"
- }
+ "version": "18.11.18",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
+ "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
},
"@types/prop-types": {
"version": "15.7.5",
@@ -3776,93 +4895,90 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA=="
},
"@vitejs/plugin-react": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz",
- "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true,
"requires": {
- "@rolldown/pluginutils": "1.0.0-rc.7"
- },
- "dependencies": {
- "@rolldown/pluginutils": {
- "version": "1.0.0-rc.7",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz",
- "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==",
- "dev": true
- }
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
}
},
"@vitest/expect": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
- "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.7.tgz",
+ "integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==",
"dev": true,
"requires": {
- "@standard-schema/spec": "^1.1.0",
- "@types/chai": "^5.2.2",
- "@vitest/spy": "4.1.6",
- "@vitest/utils": "4.1.6",
- "chai": "^6.2.2",
- "tinyrainbow": "^3.1.0"
+ "@vitest/spy": "3.0.7",
+ "@vitest/utils": "3.0.7",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
}
},
"@vitest/mocker": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz",
- "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.7.tgz",
+ "integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==",
"dev": true,
"requires": {
- "@vitest/spy": "4.1.6",
+ "@vitest/spy": "3.0.7",
"estree-walker": "^3.0.3",
- "magic-string": "^0.30.21"
+ "magic-string": "^0.30.17"
}
},
"@vitest/pretty-format": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz",
- "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.7.tgz",
+ "integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==",
"dev": true,
"requires": {
- "tinyrainbow": "^3.1.0"
+ "tinyrainbow": "^2.0.0"
}
},
"@vitest/runner": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz",
- "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.7.tgz",
+ "integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==",
"dev": true,
"requires": {
- "@vitest/utils": "4.1.6",
+ "@vitest/utils": "3.0.7",
"pathe": "^2.0.3"
}
},
"@vitest/snapshot": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz",
- "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.7.tgz",
+ "integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==",
"dev": true,
"requires": {
- "@vitest/pretty-format": "4.1.6",
- "@vitest/utils": "4.1.6",
- "magic-string": "^0.30.21",
+ "@vitest/pretty-format": "3.0.7",
+ "magic-string": "^0.30.17",
"pathe": "^2.0.3"
}
},
"@vitest/spy": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz",
- "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==",
- "dev": true
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.7.tgz",
+ "integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==",
+ "dev": true,
+ "requires": {
+ "tinyspy": "^3.0.2"
+ }
},
"@vitest/utils": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz",
- "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.7.tgz",
+ "integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==",
"dev": true,
"requires": {
- "@vitest/pretty-format": "4.1.6",
- "convert-source-map": "^2.0.0",
- "tinyrainbow": "^3.1.0"
+ "@vitest/pretty-format": "3.0.7",
+ "loupe": "^3.1.3",
+ "tinyrainbow": "^2.0.0"
}
},
"acorn": {
@@ -3919,6 +5035,18 @@
"fill-range": "^7.1.1"
}
},
+ "browserslist": {
+ "version": "4.25.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
+ "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001726",
+ "electron-to-chromium": "^1.5.173",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.3"
+ }
+ },
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -3927,6 +5055,12 @@
"optional": true,
"peer": true
},
+ "cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true
+ },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -3936,12 +5070,25 @@
"get-intrinsic": "^1.0.2"
}
},
- "chai": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
- "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "caniuse-lite": {
+ "version": "1.0.30001727",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
+ "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
"dev": true
},
+ "chai": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+ "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
+ "dev": true,
+ "requires": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ }
+ },
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -3951,6 +5098,12 @@
"supports-color": "^7.1.0"
}
},
+ "check-error": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+ "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+ "dev": true
+ },
"ci-info": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz",
@@ -3975,6 +5128,11 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
"css.escape": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -4020,6 +5178,12 @@
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
"dev": true
},
+ "deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true
+ },
"deep-equal": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz",
@@ -4053,12 +5217,6 @@
"object-keys": "^1.1.1"
}
},
- "detect-libc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true
- },
"diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -4069,6 +5227,12 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz",
"integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw=="
},
+ "electron-to-chromium": {
+ "version": "1.5.189",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.189.tgz",
+ "integrity": "sha512-y9D1ntS1ruO/pZ/V2FtLE+JXLQe28XoRpZ7QCCo0T8LdQladzdcOVQZH/IWLVJvCw12OGMb6hYOeOAjntCmJRQ==",
+ "dev": true
+ },
"entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
@@ -4091,9 +5255,48 @@
}
},
"es-module-lexer": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
- "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+ "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
+ "dev": true
+ },
+ "esbuild": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+ "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
+ "dev": true,
+ "requires": {
+ "@esbuild/aix-ppc64": "0.25.0",
+ "@esbuild/android-arm": "0.25.0",
+ "@esbuild/android-arm64": "0.25.0",
+ "@esbuild/android-x64": "0.25.0",
+ "@esbuild/darwin-arm64": "0.25.0",
+ "@esbuild/darwin-x64": "0.25.0",
+ "@esbuild/freebsd-arm64": "0.25.0",
+ "@esbuild/freebsd-x64": "0.25.0",
+ "@esbuild/linux-arm": "0.25.0",
+ "@esbuild/linux-arm64": "0.25.0",
+ "@esbuild/linux-ia32": "0.25.0",
+ "@esbuild/linux-loong64": "0.25.0",
+ "@esbuild/linux-mips64el": "0.25.0",
+ "@esbuild/linux-ppc64": "0.25.0",
+ "@esbuild/linux-riscv64": "0.25.0",
+ "@esbuild/linux-s390x": "0.25.0",
+ "@esbuild/linux-x64": "0.25.0",
+ "@esbuild/netbsd-arm64": "0.25.0",
+ "@esbuild/netbsd-x64": "0.25.0",
+ "@esbuild/openbsd-arm64": "0.25.0",
+ "@esbuild/openbsd-x64": "0.25.0",
+ "@esbuild/sunos-x64": "0.25.0",
+ "@esbuild/win32-arm64": "0.25.0",
+ "@esbuild/win32-ia32": "0.25.0",
+ "@esbuild/win32-x64": "0.25.0"
+ }
+ },
+ "escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true
},
"estree-walker": {
@@ -4118,9 +5321,9 @@
}
},
"expect-type": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
- "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz",
+ "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==",
"dev": true
},
"fill-range": {
@@ -4156,6 +5359,12 @@
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
},
+ "gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true
+ },
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@@ -4256,11 +5465,21 @@
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
},
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
"is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -4558,107 +5777,41 @@
"xml-name-validator": "^5.0.0"
}
},
- "lightningcss": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
- "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
- "dev": true,
- "requires": {
- "detect-libc": "^2.0.3",
- "lightningcss-android-arm64": "1.32.0",
- "lightningcss-darwin-arm64": "1.32.0",
- "lightningcss-darwin-x64": "1.32.0",
- "lightningcss-freebsd-x64": "1.32.0",
- "lightningcss-linux-arm-gnueabihf": "1.32.0",
- "lightningcss-linux-arm64-gnu": "1.32.0",
- "lightningcss-linux-arm64-musl": "1.32.0",
- "lightningcss-linux-x64-gnu": "1.32.0",
- "lightningcss-linux-x64-musl": "1.32.0",
- "lightningcss-win32-arm64-msvc": "1.32.0",
- "lightningcss-win32-x64-msvc": "1.32.0"
- }
- },
- "lightningcss-android-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
- "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
- "dev": true,
- "optional": true
- },
- "lightningcss-darwin-arm64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
- "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
- "dev": true,
- "optional": true
- },
- "lightningcss-darwin-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
- "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
- "dev": true,
- "optional": true
- },
- "lightningcss-freebsd-x64": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
- "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
- "dev": true,
- "optional": true
- },
- "lightningcss-linux-arm-gnueabihf": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
- "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
- "dev": true,
- "optional": true
- },
- "lightningcss-linux-arm64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
- "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
- "dev": true,
- "optional": true
- },
- "lightningcss-linux-arm64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
- "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
- "dev": true,
- "optional": true
- },
- "lightningcss-linux-x64-gnu": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
- "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
- "dev": true,
- "optional": true
+ "jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true
},
- "lightningcss-linux-x64-musl": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
- "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
- "dev": true,
- "optional": true
+ "json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true
},
- "lightningcss-win32-arm64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
- "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
- "dev": true,
- "optional": true
+ "jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
},
- "lightningcss-win32-x64-msvc": {
- "version": "1.32.0",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
- "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
- "dev": true,
- "optional": true
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "requires": {
+ "immediate": "~3.0.5"
+ }
},
"lodash": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
- "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"loose-envify": {
"version": "1.4.0",
@@ -4668,18 +5821,33 @@
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
+ "loupe": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
+ "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+ "dev": true
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
"lz-string": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
"integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ=="
},
"magic-string": {
- "version": "0.30.21",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
- "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"requires": {
- "@jridgewell/sourcemap-codec": "^1.5.5"
+ "@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"micromatch": {
@@ -4703,9 +5871,15 @@
"dev": true
},
"nanoid": {
- "version": "3.3.16",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
- "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "dev": true
+ },
+ "node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true
},
"nwsapi": {
@@ -4744,11 +5918,10 @@
"object-keys": "^1.1.1"
}
},
- "obug": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
- "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
- "dev": true
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"parse5": {
"version": "7.3.0",
@@ -4765,25 +5938,31 @@
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
+ "pathval": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+ "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+ "dev": true
+ },
"picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"picomatch": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
- "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"postcss": {
- "version": "8.5.25",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
- "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"requires": {
- "nanoid": "^3.3.16",
- "picocolors": "^1.1.1",
- "source-map-js": "^1.2.1"
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
}
},
"pretty-format": {
@@ -4803,6 +5982,11 @@
}
}
},
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
"punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4831,6 +6015,33 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
+ "react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ }
+ }
+ },
"redent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
@@ -4855,29 +6066,35 @@
"functions-have-names": "^1.2.2"
}
},
- "rolldown": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
- "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
- "dev": true,
- "requires": {
- "@oxc-project/types": "=0.133.0",
- "@rolldown/binding-android-arm64": "1.0.3",
- "@rolldown/binding-darwin-arm64": "1.0.3",
- "@rolldown/binding-darwin-x64": "1.0.3",
- "@rolldown/binding-freebsd-x64": "1.0.3",
- "@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
- "@rolldown/binding-linux-arm64-gnu": "1.0.3",
- "@rolldown/binding-linux-arm64-musl": "1.0.3",
- "@rolldown/binding-linux-ppc64-gnu": "1.0.3",
- "@rolldown/binding-linux-s390x-gnu": "1.0.3",
- "@rolldown/binding-linux-x64-gnu": "1.0.3",
- "@rolldown/binding-linux-x64-musl": "1.0.3",
- "@rolldown/binding-openharmony-arm64": "1.0.3",
- "@rolldown/binding-wasm32-wasi": "1.0.3",
- "@rolldown/binding-win32-arm64-msvc": "1.0.3",
- "@rolldown/binding-win32-x64-msvc": "1.0.3",
- "@rolldown/pluginutils": "^1.0.0"
+ "rollup": {
+ "version": "4.50.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
+ "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
+ "dev": true,
+ "requires": {
+ "@rollup/rollup-android-arm-eabi": "4.50.1",
+ "@rollup/rollup-android-arm64": "4.50.1",
+ "@rollup/rollup-darwin-arm64": "4.50.1",
+ "@rollup/rollup-darwin-x64": "4.50.1",
+ "@rollup/rollup-freebsd-arm64": "4.50.1",
+ "@rollup/rollup-freebsd-x64": "4.50.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.50.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.50.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.50.1",
+ "@rollup/rollup-linux-arm64-musl": "4.50.1",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.50.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.50.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.50.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.50.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.50.1",
+ "@rollup/rollup-linux-x64-gnu": "4.50.1",
+ "@rollup/rollup-linux-x64-musl": "4.50.1",
+ "@rollup/rollup-openharmony-arm64": "4.50.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.50.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.50.1",
+ "@rollup/rollup-win32-x64-msvc": "4.50.1",
+ "@types/estree": "1.0.8",
+ "fsevents": "~2.3.2"
}
},
"rrweb-cssom": {
@@ -4886,6 +6103,11 @@
"integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
"dev": true
},
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -4909,6 +6131,17 @@
"loose-envify": "^1.1.0"
}
},
+ "semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -4931,9 +6164,9 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
},
"source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true
},
"source-map-support": {
@@ -4980,11 +6213,19 @@
"dev": true
},
"std-env": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
- "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz",
+ "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==",
"dev": true
},
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -5038,19 +6279,19 @@
"dev": true
},
"tinyexec": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz",
- "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
"dev": true
},
"tinyglobby": {
- "version": "0.2.17",
- "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
- "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true,
"requires": {
"fdir": "^6.5.0",
- "picomatch": "^4.0.4"
+ "picomatch": "^4.0.3"
},
"dependencies": {
"fdir": {
@@ -5061,17 +6302,29 @@
"requires": {}
},
"picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true
}
}
},
+ "tinypool": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+ "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+ "dev": true
+ },
"tinyrainbow": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
- "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true
+ },
+ "tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
"dev": true
},
"tldts": {
@@ -5115,74 +6368,90 @@
"punycode": "^2.3.1"
}
},
- "tslib": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true,
- "optional": true
+ "requires": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ }
},
- "undici-types": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz",
- "integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ=="
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"vite": {
- "version": "8.0.16",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
- "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+ "version": "6.3.6",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
+ "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
"dev": true,
"requires": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
"fsevents": "~2.3.3",
- "lightningcss": "^1.32.0",
- "picomatch": "^4.0.4",
- "postcss": "^8.5.15",
- "rolldown": "1.0.3",
- "tinyglobby": "^0.2.17"
+ "picomatch": "^4.0.2",
+ "postcss": "^8.4.31",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
},
"dependencies": {
+ "fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "requires": {}
+ },
"picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true
}
}
},
+ "vite-node": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.7.tgz",
+ "integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==",
+ "dev": true,
+ "requires": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.0",
+ "es-module-lexer": "^1.6.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0"
+ }
+ },
"vitest": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz",
- "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==",
- "dev": true,
- "requires": {
- "@vitest/expect": "4.1.6",
- "@vitest/mocker": "4.1.6",
- "@vitest/pretty-format": "4.1.6",
- "@vitest/runner": "4.1.6",
- "@vitest/snapshot": "4.1.6",
- "@vitest/spy": "4.1.6",
- "@vitest/utils": "4.1.6",
- "es-module-lexer": "^2.0.0",
- "expect-type": "^1.3.0",
- "magic-string": "^0.30.21",
- "obug": "^2.1.1",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.7.tgz",
+ "integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==",
+ "dev": true,
+ "requires": {
+ "@vitest/expect": "3.0.7",
+ "@vitest/mocker": "3.0.7",
+ "@vitest/pretty-format": "^3.0.7",
+ "@vitest/runner": "3.0.7",
+ "@vitest/snapshot": "3.0.7",
+ "@vitest/spy": "3.0.7",
+ "@vitest/utils": "3.0.7",
+ "chai": "^5.2.0",
+ "debug": "^4.4.0",
+ "expect-type": "^1.1.0",
+ "magic-string": "^0.30.17",
"pathe": "^2.0.3",
- "picomatch": "^4.0.3",
- "std-env": "^4.0.0-rc.1",
+ "std-env": "^3.8.0",
"tinybench": "^2.9.0",
- "tinyexec": "^1.0.2",
- "tinyglobby": "^0.2.15",
- "tinyrainbow": "^3.1.0",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "tinyexec": "^0.3.2",
+ "tinypool": "^1.0.2",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0",
+ "vite-node": "3.0.7",
"why-is-node-running": "^2.3.0"
- },
- "dependencies": {
- "picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
- "dev": true
- }
}
},
"w3c-xmlserializer": {
@@ -5277,9 +6546,9 @@
}
},
"ws": {
- "version": "8.21.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
- "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"dev": true,
"requires": {}
},
@@ -5294,6 +6563,12 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
+ },
+ "yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
}
}
}
diff --git a/package.json b/package.json
index 011efa5f2..ea235da24 100644
--- a/package.json
+++ b/package.json
@@ -7,13 +7,15 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
+ "jszip": "^3.10.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"web-vitals": "^3.1.0"
},
"overrides": {
"@svgr/webpack": "^8.0.1",
- "@adobe/css-tools": "^4.3.1"
+ "@adobe/css-tools": "^4.3.1",
+ "postcss": "^8.4.31"
},
"scripts": {
"start": "BROWSER=none WDS_SOCKET_PORT=0 vite --port 3000",
@@ -40,9 +42,9 @@
]
},
"devDependencies": {
- "@vitejs/plugin-react": "^6.0.1",
+ "@vitejs/plugin-react": "^4.7.0",
"jsdom": "^26.1.0",
- "vite": "^8.0.16",
- "vitest": "^4.1.6"
+ "vite": "^6.3.6",
+ "vitest": "^3.0.7"
}
}
diff --git a/src/App.css b/src/App.css
index fce9cc9d8..23e932fef 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,31 +1,583 @@
-.App {
+.trading-dashboard {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+}
+
+.dashboard-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30px;
+ padding-bottom: 20px;
+ border-bottom: 2px solid #e0e0e0;
+}
+
+.dashboard-header h1 {
+ margin: 0;
+ color: #333;
+ font-size: 2rem;
+}
+
+.vendor-selector {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+ min-width: 150px;
+}
+
+.tab-navigation {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.tab {
+ padding: 12px 24px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ color: #666;
+ border-bottom: 3px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.tab:hover {
+ color: #333;
+ background-color: #f5f5f5;
+}
+
+.tab.active {
+ color: #007acc;
+ border-bottom-color: #007acc;
+}
+
+.dashboard-content {
+ min-height: 400px;
+}
+
+.tab-content {
+ padding: 20px;
+ background: #f9f9f9;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.tab-content h2 {
+ margin-top: 0;
+ color: #333;
+}
+
+.error-boundary {
+ padding: 20px;
+ background: #fff3cd;
+ border: 1px solid #ffeaa7;
+ border-radius: 8px;
+ text-align: center;
+}
+
+.error-boundary h3 {
+ color: #856404;
+ margin-top: 0;
+}
+
+.error-boundary button {
+ padding: 8px 16px;
+ background: #007acc;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-top: 10px;
+}
+
+.error-boundary button:hover {
+ background: #005a9e;
+}
+
+.fetch-controls, .analytics-controls, .bulk-controls {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+ margin-bottom: 20px;
+}
+
+.control-row {
+ display: flex;
+ gap: 15px;
+ margin-bottom: 15px;
+ flex-wrap: wrap;
+}
+
+.control-group {
+ flex: 1;
+ min-width: 150px;
+}
+
+.control-group label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: 500;
+ font-size: 14px;
+}
+
+.control-group input, .control-group select {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+}
+
+.control-group input[type="checkbox"] {
+ width: auto;
+ margin-right: 8px;
+}
+
+.fetch-btn {
+ background: #007acc;
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ width: 100%;
+ margin-top: 10px;
+}
+
+.fetch-btn:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
+
+.fetch-btn:hover:not(:disabled) {
+ background: #005a9e;
+}
+
+.quote-display {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.price-info {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin: 10px 0;
+}
+
+.price {
+ font-size: 2rem;
+ font-weight: bold;
+ color: #333;
+}
+
+.change.positive {
+ color: #28a745;
+}
+
+.change.negative {
+ color: #dc3545;
+}
+
+.historical-summary {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ margin-top: 15px;
+}
+
+.historical-summary p {
+ margin: 5px 0;
+ font-size: 14px;
+}
+
+.analytics-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 15px;
+ margin-top: 20px;
+}
+
+.metric {
+ background: white;
+ padding: 15px;
+ border-radius: 6px;
+ border: 1px solid #e0e0e0;
text-align: center;
}
-.App-logo {
- height: 40vmin;
- pointer-events: none;
+.metric label {
+ display: block;
+ font-size: 12px;
+ color: #666;
+ margin-bottom: 5px;
+}
+
+.metric span {
+ font-size: 16px;
+ font-weight: bold;
+}
+
+.volatility.high, .recommendation.sell {
+ color: #dc3545;
+}
+
+.volatility.medium, .recommendation.hold {
+ color: #ffc107;
+}
+
+.volatility.low, .recommendation.buy, .trend.up {
+ color: #28a745;
+}
+
+.trend.down {
+ color: #dc3545;
+}
+
+.bulk-downloader {
+ margin-top: 30px;
+ padding: 20px;
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.download-results {
+ margin-top: 15px;
+ padding: 10px;
+ background: #d4edda;
+ border: 1px solid #c3e6cb;
+ border-radius: 4px;
+ color: #155724;
+}
+
+.admin-nav {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
+}
+
+.admin-btn {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ background: white;
+ cursor: pointer;
+ border-radius: 4px;
+}
+
+.admin-btn.active {
+ background: #007acc;
+ color: white;
+ border-color: #007acc;
+}
+
+.code-viewer {
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.code-tabs {
+ display: flex;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.code-tab {
+ padding: 12px 20px;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-bottom: 3px solid transparent;
+}
+
+.code-tab.active {
+ background: #f8f9fa;
+ border-bottom-color: #007acc;
+}
+
+.code-display {
+ padding: 20px;
+}
+
+.code-block {
+ background: #f8f9fa;
+ padding: 15px;
+ border-radius: 6px;
+ overflow-x: auto;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 13px;
+ line-height: 1.4;
+ border: 1px solid #e9ecef;
+}
+
+.vendor-status {
+ background: white;
+ padding: 20px;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.status-btn {
+ background: #28a745;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-bottom: 20px;
+}
+
+.status-grid {
+ display: grid;
+ gap: 15px;
+}
+
+.status-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ background: #f8f9fa;
+ border-radius: 4px;
+}
+
+.status-item label {
+ font-weight: 500;
+}
+
+.connected {
+ color: #28a745;
+}
+
+.disconnected {
+ color: #dc3545;
+}
+
+.capabilities {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.capability {
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.capability.enabled {
+ background: #d4edda;
+ color: #155724;
+}
+
+.capability.disabled {
+ background: #f8d7da;
+ color: #721c24;
+}
+
+.code-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.edit-toggle {
+ padding: 6px 12px;
+ border: 1px solid #007acc;
+ background: white;
+ color: #007acc;
+ cursor: pointer;
+ border-radius: 4px;
+ margin: 10px;
+ font-size: 12px;
+}
+
+.edit-toggle.active {
+ background: #007acc;
+ color: white;
+}
+
+.code-editor {
+ background: white;
+}
+
+.editor-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 15px;
+ border-bottom: 1px solid #e0e0e0;
+ background: #f8f9fa;
}
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
+.editor-controls {
display: flex;
- flex-direction: column;
+ gap: 8px;
+}
+
+.history-btn, .save-btn {
+ padding: 4px 8px;
+ border: 1px solid #ddd;
+ background: white;
+ cursor: pointer;
+ border-radius: 3px;
+ font-size: 11px;
+}
+
+.save-btn {
+ background: #28a745;
+ color: white;
+ border-color: #28a745;
+}
+
+.code-textarea {
+ width: 100%;
+ min-height: 300px;
+ padding: 15px;
+ border: none;
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 12px;
+ line-height: 1.4;
+ resize: vertical;
+ outline: none;
+ background: #f8f9fa;
+}
+
+.code-history {
+ background: #fff3cd;
+ padding: 10px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+.history-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px 8px;
+ margin: 3px 0;
+ background: white;
+ border-radius: 3px;
+ border: 1px solid #e0e0e0;
+}
+
+.history-time {
+ font-size: 11px;
+ color: #666;
+}
+
+.revert-btn {
+ padding: 2px 6px;
+ background: #ffc107;
+ color: #212529;
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+ font-size: 10px;
+}
+
+.code-actions {
+ display: flex;
+ gap: 8px;
align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
+}
+
+.download-btn {
+ padding: 6px 12px;
+ border: 1px solid #28a745;
+ background: white;
+ color: #28a745;
+ cursor: pointer;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.download-btn:hover {
+ background: #28a745;
+ color: white;
+}
+
+.tree-viewer {
+ background: white;
+ border-radius: 8px;
+ border: 1px solid #e0e0e0;
+}
+
+.tree-controls {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 15px;
+ border-bottom: 1px solid #e0e0e0;
+ background: #f8f9fa;
+}
+
+.tree-option {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+}
+
+.tree-actions {
+ display: flex;
+ gap: 10px;
+}
+
+.tree-btn {
+ padding: 6px 12px;
+ border: 1px solid #007acc;
+ background: white;
+ color: #007acc;
+ cursor: pointer;
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+.tree-btn:hover {
+ background: #007acc;
+ color: white;
+}
+
+.tree-btn.download {
+ border-color: #28a745;
+ color: #28a745;
+}
+
+.tree-btn.download:hover {
+ background: #28a745;
color: white;
}
-.App-link {
- color: #61dafb;
+.tree-btn:disabled {
+ background: #f8f9fa;
+ color: #ccc;
+ border-color: #ccc;
+ cursor: not-allowed;
}
-.heart {
- color: #ff0000;
+.tree-display {
+ padding: 20px;
+ max-height: 500px;
+ overflow-y: auto;
}
-.small {
- font-size: 0.75rem;
+.tree-content {
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 12px;
+ line-height: 1.4;
+ margin: 0;
+ white-space: pre;
+ color: #333;
}
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 8b32d0718..f3a1bf21a 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,29 +1,24 @@
+import React, { useEffect } from 'react';
import './App.css';
+import TradingDashboard from './components/TradingDashboard';
+import VendorManager from './core/VendorManager';
+import ExampleVendorA from './vendors/ExampleVendorA';
+import ExampleVendorB from './vendors/ExampleVendorB';
+import YFinanceVendor from './vendors/YFinanceVendor';
function App() {
+ useEffect(() => {
+ // Register vendors on app startup
+ VendorManager.registerVendor('vendorA', new ExampleVendorA());
+ VendorManager.registerVendor('vendorB', new ExampleVendorB());
+ VendorManager.registerVendor('yfinance', new YFinanceVendor());
+ }, []);
+
return (
);
}
-export default App;
+export default App;
\ No newline at end of file
diff --git a/src/components/AdminComponents.jsx b/src/components/AdminComponents.jsx
new file mode 100644
index 000000000..515e6ab6e
--- /dev/null
+++ b/src/components/AdminComponents.jsx
@@ -0,0 +1,365 @@
+import React, { useState } from 'react';
+import VendorManager from '../core/VendorManager';
+import { CodeEditor } from './CodeEditor';
+
+export const CodeViewer = ({ vendor }) => {
+ const [activeCode, setActiveCode] = useState('fetch');
+ const [editMode, setEditMode] = useState(false);
+ const [customCode, setCustomCode] = useState({});
+
+ const codeExamples = {
+ fetch: {
+ title: 'Data Fetching Code',
+ code: `// Market Data Fetch
+const fetchMarketData = async (symbol, interval = '1d') => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseYahooResponse(data, symbol);
+};
+
+// Historical Data Fetch
+const fetchHistoricalData = async (symbol, interval, period) => {
+ const url = \`https://query1.finance.yahoo.com/v8/finance/chart/\${symbol}?interval=\${interval}&range=\${period}\`;
+ const response = await fetch(url);
+ const data = await response.json();
+ return parseHistoricalData(data, symbol);
+};
+
+// Bulk Download
+const bulkDownload = async (symbols, intervals, options) => {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ const data = await fetchHistoricalData(symbol, interval, options.period);
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ }
+ }
+
+ // Rate limiting
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return results;
+};`
+ },
+ parser: {
+ title: 'Data Parser Code',
+ code: `// Yahoo Response Parser
+const parseYahooResponse = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+};
+
+// Historical Data Parser
+const parseHistoricalData = (data, symbol) => {
+ const chart = data.chart?.result?.[0];
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+};`
+ },
+ analytics: {
+ title: 'Analytics Code',
+ code: `// Volatility Calculator
+const calculateVolatility = (dailyData, weeklyData) => {
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+};
+
+// Recommendation Generator
+const generateRecommendation = (data) => {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+};
+
+// Analytics Fetch
+const getAnalytics = async (symbol, timeframe = '1mo') => {
+ const [daily, weekly] = await Promise.all([
+ getMarketData(symbol, '1d'),
+ getMarketData(symbol, '1wk')
+ ]);
+
+ return {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ volatility: calculateVolatility(daily.data, weekly.data),
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ recommendation: generateRecommendation(daily.data)
+ };
+};`
+ },
+ vendor: {
+ title: 'Vendor Adapter Code',
+ code: `// YFinance Vendor Class
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = \`\${symbol}_\${interval}\`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ const url = \`\${this.config.baseUrl}\${symbol}?interval=\${interval}&range=1d\`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+}`
+ }
+ };
+
+ const handleCodeSave = (code) => {
+ setCustomCode(prev => ({
+ ...prev,
+ [activeCode]: code
+ }));
+ };
+
+ const getCurrentCode = () => {
+ return customCode[activeCode] || codeExamples[activeCode].code;
+ };
+
+ const downloadCode = (codeType) => {
+ const code = getCurrentCode();
+ const filename = `${codeType}_code.js`;
+ const blob = new Blob([code], { type: 'text/javascript' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ a.click();
+ URL.revokeObjectURL(url);
+ };
+
+ const downloadBundle = () => {
+ const bundle = Object.entries(codeExamples).map(([key, example]) => {
+ const code = customCode[key] || example.code;
+ return `// ========== ${example.title} ==========\n${code}\n\n`;
+ }).join('');
+
+ const filename = `trading_dashboard_bundle.js`;
+ const blob = new Blob([bundle], { type: 'text/javascript' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ a.click();
+ URL.revokeObjectURL(url);
+ };
+
+ return (
+
+
+
+ {Object.entries(codeExamples).map(([key, example]) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+ {editMode ? (
+
+ ) : (
+
+
{codeExamples[activeCode].title}
+
+ {getCurrentCode()}
+
+
+ )}
+
+
+ );
+};
+
+export const VendorStatus = ({ vendor }) => {
+ const [status, setStatus] = useState(null);
+
+ const checkStatus = async () => {
+ try {
+ const vendorInstance = VendorManager.getVendor(vendor);
+ const capabilities = VendorManager.getVendorCapabilities(vendor);
+
+ setStatus({
+ name: vendorInstance?.name || 'Unknown',
+ connected: vendorInstance?.isConnected || false,
+ capabilities,
+ cacheSize: vendorInstance?.cache?.size || 0
+ });
+ } catch (error) {
+ setStatus({ error: error.message });
+ }
+ };
+
+ return (
+
+
+
+ {status && (
+
+ {status.error ? (
+
Error: {status.error}
+ ) : (
+
+
+
+ {status.name}
+
+
+
+
+ {status.connected ? 'Connected' : 'Disconnected'}
+
+
+
+
+ {status.cacheSize} items
+
+
+
+
+ {Object.entries(status.capabilities).map(([cap, enabled]) => (
+
+ {cap}: {enabled ? '✓' : '✗'}
+
+ ))}
+
+
+
+ )}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/components/CodeEditor.jsx b/src/components/CodeEditor.jsx
new file mode 100644
index 000000000..c499444bf
--- /dev/null
+++ b/src/components/CodeEditor.jsx
@@ -0,0 +1,75 @@
+import React, { useState, useEffect } from 'react';
+
+export const CodeEditor = ({ initialCode, title, onSave }) => {
+ const [code, setCode] = useState(initialCode);
+ const [history, setHistory] = useState([]);
+ const [showHistory, setShowHistory] = useState(false);
+
+ useEffect(() => {
+ setCode(initialCode);
+ }, [initialCode]);
+
+ const saveCode = () => {
+ const newVersion = {
+ code,
+ timestamp: new Date().toISOString(),
+ id: Date.now()
+ };
+
+ const newHistory = [newVersion, ...history].slice(0, 5);
+ setHistory(newHistory);
+
+ if (onSave) onSave(code);
+ };
+
+ const revertToVersion = (version) => {
+ setCode(version.code);
+ setShowHistory(false);
+ };
+
+ return (
+
+
+
{title}
+
+
+
+
+
+
+ {showHistory && (
+
+
Version History (Last 5)
+ {history.length === 0 ? (
+
No saved versions yet
+ ) : (
+ history.map((version) => (
+
+
+ {new Date(version.timestamp).toLocaleString()}
+
+
+
+ ))
+ )}
+
+ )}
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/components/ErrorBoundary.jsx b/src/components/ErrorBoundary.jsx
new file mode 100644
index 000000000..9028075a8
--- /dev/null
+++ b/src/components/ErrorBoundary.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+
+class ErrorBoundary extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error, errorInfo) {
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+
Something went wrong
+
{this.props.fallbackMessage || 'This section is temporarily unavailable'}
+
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
\ No newline at end of file
diff --git a/src/components/TradingDashboard.jsx b/src/components/TradingDashboard.jsx
new file mode 100644
index 000000000..3b2e7b934
--- /dev/null
+++ b/src/components/TradingDashboard.jsx
@@ -0,0 +1,178 @@
+import React, { useState, useEffect } from 'react';
+import ErrorBoundary from './ErrorBoundary';
+import VendorManager from '../core/VendorManager';
+import { YFinanceMarketData, YFinanceAnalytics, YFinanceBulkDownloader } from './YFinanceComponents';
+import { CodeViewer, VendorStatus } from './AdminComponents';
+import { TreeViewer } from './TreeViewer';
+
+const TradingDashboard = () => {
+ const [activeTab, setActiveTab] = useState('market');
+ const [vendors, setVendors] = useState([]);
+ const [selectedVendor, setSelectedVendor] = useState('');
+
+ useEffect(() => {
+ setVendors(VendorManager.getAllVendors());
+ if (VendorManager.getAllVendors().length > 0) {
+ setSelectedVendor(VendorManager.getAllVendors()[0]);
+ }
+ }, []);
+
+ const tabs = [
+ { id: 'market', label: 'Market Data', capability: 'marketData' },
+ { id: 'orders', label: 'Orders', capability: 'orderManagement' },
+ { id: 'portfolio', label: 'Portfolio', capability: 'portfolio' },
+ { id: 'analytics', label: 'Analytics', capability: 'analytics' },
+ { id: 'admin', label: 'Admin', capability: 'admin' }
+ ];
+
+ const getAvailableTabs = () => {
+ if (!selectedVendor) return [];
+ const capabilities = VendorManager.getVendorCapabilities(selectedVendor);
+ return tabs.filter(tab => tab.capability === 'admin' || capabilities[tab.capability]);
+ };
+
+ const renderTabContent = () => {
+ const availableTabs = getAvailableTabs();
+ const currentTab = availableTabs.find(tab => tab.id === activeTab);
+
+ if (!currentTab) {
+ return Feature not available for selected vendor
;
+ }
+
+ switch (activeTab) {
+ case 'market':
+ return ;
+ case 'orders':
+ return ;
+ case 'portfolio':
+ return ;
+ case 'analytics':
+ return ;
+ case 'admin':
+ return ;
+ default:
+ return Select a tab
;
+ }
+ };
+
+ return (
+
+
+ Trading Dashboard
+
+
+
+
+
+
+
+ {renderTabContent()}
+
+
+
+ );
+};
+
+const MarketDataTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Market Data - Yahoo Finance
+
+
+ );
+ }
+ return (
+
+
Market Data - {vendor}
+
Market data functionality for {vendor}
+
+ );
+};
+
+const OrdersTab = ({ vendor }) => (
+
+
Order Management - {vendor}
+
Order management functionality for {vendor}
+
+);
+
+const PortfolioTab = ({ vendor }) => (
+
+
Portfolio - {vendor}
+
Portfolio functionality for {vendor}
+
+);
+
+const AnalyticsTab = ({ vendor }) => {
+ if (vendor === 'yfinance') {
+ return (
+
+
Analytics - Yahoo Finance
+
+
+
+ );
+ }
+ return (
+
+
Analytics - {vendor}
+
Analytics functionality for {vendor}
+
+ );
+};
+
+const AdminTab = ({ vendor }) => {
+ const [activeAdmin, setActiveAdmin] = useState('code');
+
+ return (
+
+
Admin - {vendor}
+
+
+
+
+
+
+ {activeAdmin === 'code' &&
}
+ {activeAdmin === 'status' &&
}
+ {activeAdmin === 'tree' &&
}
+
+ );
+};
+
+export default TradingDashboard;
\ No newline at end of file
diff --git a/src/components/TreeViewer.jsx b/src/components/TreeViewer.jsx
new file mode 100644
index 000000000..bbf9932b7
--- /dev/null
+++ b/src/components/TreeViewer.jsx
@@ -0,0 +1,198 @@
+import React, { useState, useEffect } from 'react';
+import JSZip from 'jszip';
+
+export const TreeViewer = () => {
+ const [treeData, setTreeData] = useState('');
+ const [includeFiles, setIncludeFiles] = useState(false);
+ const [loading, setLoading] = useState(false);
+
+ const generateTree = async () => {
+ setLoading(true);
+ try {
+ const tree = await buildProjectTree(includeFiles);
+ setTreeData(tree);
+ } catch (error) {
+ setTreeData(`Error generating tree: ${error.message}`);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const buildProjectTree = async (withFiles) => {
+ const structure = {
+ 'src/': {
+ 'core/': {
+ 'VendorManager.js': withFiles ? await fetchFileContent('/src/core/VendorManager.js') : null,
+ 'BaseVendorAdapter.js': withFiles ? await fetchFileContent('/src/core/BaseVendorAdapter.js') : null
+ },
+ 'vendors/': {
+ 'YFinanceVendor.js': withFiles ? await fetchFileContent('/src/vendors/YFinanceVendor.js') : null,
+ 'ExampleVendorA.js': withFiles ? await fetchFileContent('/src/vendors/ExampleVendorA.js') : null,
+ 'ExampleVendorB.js': withFiles ? await fetchFileContent('/src/vendors/ExampleVendorB.js') : null,
+ 'VendorTemplate.js': withFiles ? await fetchFileContent('/src/vendors/VendorTemplate.js') : null
+ },
+ 'components/': {
+ 'TradingDashboard.jsx': withFiles ? await fetchFileContent('/src/components/TradingDashboard.jsx') : null,
+ 'YFinanceComponents.jsx': withFiles ? await fetchFileContent('/src/components/YFinanceComponents.jsx') : null,
+ 'AdminComponents.jsx': withFiles ? await fetchFileContent('/src/components/AdminComponents.jsx') : null,
+ 'CodeEditor.jsx': withFiles ? await fetchFileContent('/src/components/CodeEditor.jsx') : null,
+ 'ErrorBoundary.jsx': withFiles ? await fetchFileContent('/src/components/ErrorBoundary.jsx') : null
+ },
+ 'utils/': {
+ 'VendorRegistry.js': withFiles ? await fetchFileContent('/src/utils/VendorRegistry.js') : null
+ },
+ 'App.jsx': withFiles ? await fetchFileContent('/src/App.jsx') : null,
+ 'App.css': withFiles ? await fetchFileContent('/src/App.css') : null,
+ 'index.jsx': withFiles ? await fetchFileContent('/src/index.jsx') : null
+ },
+ 'public/': {
+ 'index.html': null,
+ 'favicon.ico': null
+ },
+ 'package.json': withFiles ? await fetchFileContent('/package.json') : null,
+ 'vite.config.js': withFiles ? await fetchFileContent('/vite.config.js') : null,
+ 'README.md': null
+ };
+
+ return formatTree(structure, '', withFiles);
+ };
+
+ const fetchFileContent = async (path) => {
+ try {
+ const response = await fetch(path);
+ if (response.ok) {
+ return await response.text();
+ }
+ } catch (error) {
+ return `// Error loading file: ${error.message}`;
+ }
+ return null;
+ };
+
+ const formatTree = (obj, prefix = '', withFiles = false, isLast = true) => {
+ let result = '';
+ const entries = Object.entries(obj);
+
+ entries.forEach(([key, value], index) => {
+ const isLastItem = index === entries.length - 1;
+ const connector = isLastItem ? '└── ' : '├── ';
+ const nextPrefix = prefix + (isLastItem ? ' ' : '│ ');
+
+ result += `${prefix}${connector}${key}\n`;
+
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
+ result += formatTree(value, nextPrefix, withFiles, isLastItem);
+ } else if (withFiles && value && typeof value === 'string') {
+ const fileLines = value.split('\n');
+ const preview = fileLines.slice(0, 3).join('\n');
+ result += `${nextPrefix}┌─ Content (${fileLines.length} lines):\n`;
+ result += `${nextPrefix}│ ${preview.replace(/\n/g, `\n${nextPrefix}│ `)}\n`;
+ if (fileLines.length > 3) {
+ result += `${nextPrefix}│ ...\n`;
+ }
+ result += `${nextPrefix}└─\n`;
+ }
+ });
+
+ return result;
+ };
+
+ const downloadTree = () => {
+ const filename = includeFiles ? 'project_tree_with_files.txt' : 'project_tree.txt';
+ const blob = new Blob([treeData], { type: 'text/plain' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ a.click();
+ URL.revokeObjectURL(url);
+ };
+
+ const downloadZip = async () => {
+ setLoading(true);
+ try {
+ const zip = new JSZip();
+
+ // Add project structure files
+ const files = {
+ 'src/core/VendorManager.js': await fetchFileContent('/src/core/VendorManager.js'),
+ 'src/core/BaseVendorAdapter.js': await fetchFileContent('/src/core/BaseVendorAdapter.js'),
+ 'src/vendors/YFinanceVendor.js': await fetchFileContent('/src/vendors/YFinanceVendor.js'),
+ 'src/vendors/ExampleVendorA.js': await fetchFileContent('/src/vendors/ExampleVendorA.js'),
+ 'src/vendors/ExampleVendorB.js': await fetchFileContent('/src/vendors/ExampleVendorB.js'),
+ 'src/vendors/VendorTemplate.js': await fetchFileContent('/src/vendors/VendorTemplate.js'),
+ 'src/components/TradingDashboard.jsx': await fetchFileContent('/src/components/TradingDashboard.jsx'),
+ 'src/components/YFinanceComponents.jsx': await fetchFileContent('/src/components/YFinanceComponents.jsx'),
+ 'src/components/AdminComponents.jsx': await fetchFileContent('/src/components/AdminComponents.jsx'),
+ 'src/components/CodeEditor.jsx': await fetchFileContent('/src/components/CodeEditor.jsx'),
+ 'src/components/ErrorBoundary.jsx': await fetchFileContent('/src/components/ErrorBoundary.jsx'),
+ 'src/components/TreeViewer.jsx': await fetchFileContent('/src/components/TreeViewer.jsx'),
+ 'src/utils/VendorRegistry.js': await fetchFileContent('/src/utils/VendorRegistry.js'),
+ 'src/App.jsx': await fetchFileContent('/src/App.jsx'),
+ 'src/App.css': await fetchFileContent('/src/App.css'),
+ 'src/index.jsx': await fetchFileContent('/src/index.jsx'),
+ 'package.json': await fetchFileContent('/package.json'),
+ 'vite.config.js': await fetchFileContent('/vite.config.js'),
+ 'README.md': await fetchFileContent('/README.md')
+ };
+
+ // Add tree structure
+ zip.file('PROJECT_STRUCTURE.txt', treeData);
+
+ // Add all files to zip
+ Object.entries(files).forEach(([path, content]) => {
+ if (content) {
+ zip.file(path, content);
+ }
+ });
+
+ const zipBlob = await zip.generateAsync({ type: 'blob' });
+ const url = URL.createObjectURL(zipBlob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'trading_dashboard_project.zip';
+ a.click();
+ URL.revokeObjectURL(url);
+ } catch (error) {
+ console.error('Error creating zip:', error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ generateTree();
+ }, []);
+
+ return (
+
+
+
+
+
+
+ {includeFiles && (
+
+ )}
+
+
+
+
+
{treeData || 'Generating tree structure...'}
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/components/YFinanceComponents.jsx b/src/components/YFinanceComponents.jsx
new file mode 100644
index 000000000..a9ece5aec
--- /dev/null
+++ b/src/components/YFinanceComponents.jsx
@@ -0,0 +1,339 @@
+import React, { useState, useEffect } from 'react';
+import VendorManager from '../core/VendorManager';
+
+export const YFinanceMarketData = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [assetType, setAssetType] = useState('stocks');
+ const [interval, setInterval] = useState('1d');
+ const [period, setPeriod] = useState('1mo');
+ const [customStart, setCustomStart] = useState('');
+ const [customEnd, setCustomEnd] = useState('');
+ const [useCustomRange, setUseCustomRange] = useState(false);
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const assetTypes = {
+ stocks: { label: 'Stocks', examples: 'AAPL, GOOGL, MSFT' },
+ forex: { label: 'Forex', examples: 'EURUSD=X, GBPUSD=X, USDJPY=X' },
+ crypto: { label: 'Crypto', examples: 'BTC-USD, ETH-USD, ADA-USD' },
+ commodities: { label: 'Commodities', examples: 'GC=F, CL=F, SI=F' },
+ indices: { label: 'Indices', examples: '^GSPC, ^DJI, ^IXIC' }
+ };
+
+ const intervals = ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', '10y', 'ytd', 'max'];
+
+ const fetchData = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ setError(null);
+
+ try {
+ const fetchParams = {
+ symbol: symbol.toUpperCase(),
+ interval,
+ period: useCustomRange ? null : period,
+ start: useCustomRange ? customStart : null,
+ end: useCustomRange ? customEnd : null
+ };
+
+ const result = useCustomRange || period !== '1d'
+ ? await VendorManager.executeVendorMethod(vendor, 'getHistoricalData', fetchParams.symbol, fetchParams.interval, fetchParams.period || '1mo')
+ : await VendorManager.executeVendorMethod(vendor, 'getMarketData', fetchParams.symbol, fetchParams.interval);
+
+ if (result.success) {
+ setData(result.data);
+ } else {
+ setError(result.error);
+ }
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder={assetTypes[assetType].examples}
+ onKeyPress={(e) => e.key === 'Enter' && fetchData()}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {useCustomRange ? (
+
+ ) : (
+
+
+
+
+
+
+ )}
+
+
+
+
+ {error &&
Error: {error}
}
+
+ {data && (
+
+
{data.symbol}
+ {data.price ? (
+
+ ${data.price?.toFixed(2)}
+ = 0 ? 'positive' : 'negative'}`}>
+ {data.change >= 0 ? '+' : ''}{data.change?.toFixed(2)}
+ ({data.changePercent?.toFixed(2)}%)
+
+
+ ) : null}
+ {data.data && (
+
+
Historical data: {data.data.length} records
+
Latest: ${data.data[data.data.length - 1]?.close?.toFixed(2)}
+
+ )}
+
+ )}
+
+ );
+};
+
+export const YFinanceAnalytics = ({ vendor }) => {
+ const [symbol, setSymbol] = useState('AAPL');
+ const [timeframe, setTimeframe] = useState('1mo');
+ const [analytics, setAnalytics] = useState(null);
+ const [loading, setLoading] = useState(false);
+
+ const timeframes = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y'];
+
+ const fetchAnalytics = async () => {
+ if (!symbol.trim()) return;
+
+ setLoading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(vendor, 'getAnalytics', symbol.toUpperCase(), timeframe);
+ if (result.success) {
+ setAnalytics(result.data);
+ }
+ } catch (err) {
+ console.error('Analytics error:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+ setSymbol(e.target.value)}
+ placeholder="Enter symbol for analysis"
+ onKeyPress={(e) => e.key === 'Enter' && fetchAnalytics()}
+ />
+
+
+
+
+
+
+
+
+ {analytics && (
+
+
Analysis for {analytics.symbol} ({timeframe})
+
+
+
+ ${analytics.price?.toFixed(2)}
+
+
+
+
+ {analytics.volatility}
+
+
+
+
+
+ {analytics.weeklyTrend}
+
+
+
+
+
+ {analytics.recommendation}
+
+
+
+
+ )}
+
+ );
+};
+
+export const YFinanceBulkDownloader = ({ vendor }) => {
+ const [symbols, setSymbols] = useState('AAPL,GOOGL,MSFT');
+ const [intervals, setIntervals] = useState(['1d']);
+ const [period, setPeriod] = useState('1mo');
+ const [batchSize, setBatchSize] = useState(5);
+ const [downloading, setDownloading] = useState(false);
+ const [results, setResults] = useState(null);
+
+ const availableIntervals = ['1m', '5m', '15m', '1h', '1d', '1wk', '1mo'];
+ const periods = ['1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y', 'max'];
+
+ const handleBulkDownload = async () => {
+ const symbolList = symbols.split(',').map(s => s.trim().toUpperCase()).filter(s => s);
+ if (symbolList.length === 0) return;
+
+ setDownloading(true);
+ try {
+ const result = await VendorManager.executeVendorMethod(
+ vendor,
+ 'bulkDownload',
+ symbolList,
+ intervals,
+ { period, batchSize }
+ );
+ setResults(result);
+ } catch (err) {
+ console.error('Bulk download error:', err);
+ } finally {
+ setDownloading(false);
+ }
+ };
+
+ return (
+
+
Bulk Historical Data Download
+
+
+
+ setSymbols(e.target.value)}
+ placeholder="AAPL,GOOGL,MSFT,BTC-USD,EURUSD=X"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ setBatchSize(parseInt(e.target.value))}
+ min="1"
+ max="50"
+ />
+
+
+
+
+
+ {results && (
+
+
Download Complete
+
Downloaded data for {Object.keys(results.data || {}).length} symbols
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/core/BaseVendorAdapter.js b/src/core/BaseVendorAdapter.js
new file mode 100644
index 000000000..f5f979cd7
--- /dev/null
+++ b/src/core/BaseVendorAdapter.js
@@ -0,0 +1,51 @@
+export class BaseVendorAdapter {
+ constructor(name, config = {}) {
+ this.name = name;
+ this.config = config;
+ this.isConnected = false;
+ }
+
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ throw new Error('connect() must be implemented by vendor adapter');
+ }
+
+ async disconnect() {
+ this.isConnected = false;
+ }
+
+ async getMarketData(symbol) {
+ throw new Error('getMarketData() not implemented');
+ }
+
+ async placeOrder(orderData) {
+ throw new Error('placeOrder() not implemented');
+ }
+
+ async getPortfolio() {
+ throw new Error('getPortfolio() not implemented');
+ }
+
+ async getAnalytics(symbol) {
+ throw new Error('getAnalytics() not implemented');
+ }
+
+ handleError(error, context) {
+ console.error(`${this.name} Error in ${context}:`, error);
+ return {
+ success: false,
+ error: error.message,
+ vendor: this.name,
+ context
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/core/VendorManager.js b/src/core/VendorManager.js
new file mode 100644
index 000000000..b4bafabc8
--- /dev/null
+++ b/src/core/VendorManager.js
@@ -0,0 +1,54 @@
+class VendorManager {
+ constructor() {
+ this.vendors = new Map();
+ this.capabilities = new Map();
+ }
+
+ registerVendor(vendorId, vendorAdapter) {
+ try {
+ if (!vendorAdapter.name || !vendorAdapter.getCapabilities) {
+ throw new Error(`Invalid vendor adapter for ${vendorId}`);
+ }
+
+ this.vendors.set(vendorId, vendorAdapter);
+ this.capabilities.set(vendorId, vendorAdapter.getCapabilities());
+ return true;
+ } catch (error) {
+ console.error(`Failed to register vendor ${vendorId}:`, error);
+ return false;
+ }
+ }
+
+ getVendor(vendorId) {
+ return this.vendors.get(vendorId);
+ }
+
+ getVendorCapabilities(vendorId) {
+ return this.capabilities.get(vendorId) || {};
+ }
+
+ getAllVendors() {
+ return Array.from(this.vendors.keys());
+ }
+
+ getVendorsWithCapability(capability) {
+ return Array.from(this.vendors.keys()).filter(vendorId =>
+ this.getVendorCapabilities(vendorId)[capability]
+ );
+ }
+
+ async executeVendorMethod(vendorId, method, ...args) {
+ try {
+ const vendor = this.getVendor(vendorId);
+ if (!vendor || !vendor[method]) {
+ throw new Error(`Method ${method} not available for vendor ${vendorId}`);
+ }
+ return await vendor[method](...args);
+ } catch (error) {
+ console.error(`Error executing ${method} for vendor ${vendorId}:`, error);
+ throw error;
+ }
+ }
+}
+
+export default new VendorManager();
\ No newline at end of file
diff --git a/src/utils/VendorRegistry.js b/src/utils/VendorRegistry.js
new file mode 100644
index 000000000..cb45320c8
--- /dev/null
+++ b/src/utils/VendorRegistry.js
@@ -0,0 +1,56 @@
+import VendorManager from '../core/VendorManager';
+
+export const registerNewVendor = (vendorId, VendorClass, config = {}) => {
+ try {
+ const vendorInstance = new VendorClass(config);
+ const success = VendorManager.registerVendor(vendorId, vendorInstance);
+
+ if (success) {
+ console.log(`✅ Vendor ${vendorId} registered successfully`);
+ return true;
+ } else {
+ console.error(`❌ Failed to register vendor ${vendorId}`);
+ return false;
+ }
+ } catch (error) {
+ console.error(`❌ Error registering vendor ${vendorId}:`, error);
+ return false;
+ }
+};
+
+export const getVendorInfo = (vendorId) => {
+ const vendor = VendorManager.getVendor(vendorId);
+ const capabilities = VendorManager.getVendorCapabilities(vendorId);
+
+ return {
+ exists: !!vendor,
+ name: vendor?.name || 'Unknown',
+ capabilities,
+ isConnected: vendor?.isConnected || false
+ };
+};
+
+export const testVendor = async (vendorId) => {
+ try {
+ const vendor = VendorManager.getVendor(vendorId);
+ if (!vendor) {
+ return { success: false, error: 'Vendor not found' };
+ }
+
+ const connectionResult = await vendor.connect();
+ const capabilities = vendor.getCapabilities();
+
+ return {
+ success: true,
+ connection: connectionResult,
+ capabilities,
+ vendor: vendor.name
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: error.message,
+ vendor: vendorId
+ };
+ }
+};
\ No newline at end of file
diff --git a/src/vendors/ExampleVendorA.js b/src/vendors/ExampleVendorA.js
new file mode 100644
index 000000000..46f8cdd42
--- /dev/null
+++ b/src/vendors/ExampleVendorA.js
@@ -0,0 +1,76 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorA extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor A', {
+ apiUrl: 'https://api.vendora.com',
+ apiKey: 'your-api-key'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: true,
+ portfolio: true,
+ analytics: false,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 100,
+ change: Math.random() * 10 - 5,
+ volume: Math.floor(Math.random() * 1000000)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async placeOrder(orderData) {
+ try {
+ return {
+ success: true,
+ orderId: `VA_${Date.now()}`,
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ async getPortfolio() {
+ try {
+ return {
+ success: true,
+ data: {
+ totalValue: 50000,
+ positions: [
+ { symbol: 'AAPL', quantity: 10, value: 1500 },
+ { symbol: 'GOOGL', quantity: 5, value: 12500 }
+ ]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+}
+
+export default ExampleVendorA;
\ No newline at end of file
diff --git a/src/vendors/ExampleVendorB.js b/src/vendors/ExampleVendorB.js
new file mode 100644
index 000000000..66167fc33
--- /dev/null
+++ b/src/vendors/ExampleVendorB.js
@@ -0,0 +1,66 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class ExampleVendorB extends BaseVendorAdapter {
+ constructor() {
+ super('Vendor B', {
+ baseUrl: 'https://vendorb-api.com/v2',
+ token: 'bearer-token'
+ });
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: false
+ };
+ }
+
+ async connect() {
+ try {
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: Math.random() * 200,
+ bid: Math.random() * 190,
+ ask: Math.random() * 210,
+ timestamp: Date.now()
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ return {
+ success: true,
+ data: {
+ symbol,
+ rsi: Math.random() * 100,
+ macd: Math.random() * 5 - 2.5,
+ sma20: Math.random() * 150,
+ sma50: Math.random() * 140,
+ recommendation: ['BUY', 'SELL', 'HOLD'][Math.floor(Math.random() * 3)]
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+}
+
+export default ExampleVendorB;
\ No newline at end of file
diff --git a/src/vendors/VendorTemplate.js b/src/vendors/VendorTemplate.js
new file mode 100644
index 000000000..c411953db
--- /dev/null
+++ b/src/vendors/VendorTemplate.js
@@ -0,0 +1,141 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+/**
+ * Template for creating new vendor adapters
+ * Copy this file and implement your vendor-specific logic
+ */
+class VendorTemplate extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Vendor Name', {
+ apiUrl: config.apiUrl || '',
+ apiKey: config.apiKey || '',
+ ...config
+ });
+ }
+
+ /**
+ * Define what this vendor can do
+ * Set to true only for features this vendor supports
+ */
+ getCapabilities() {
+ return {
+ marketData: false,
+ orderManagement: false,
+ portfolio: false,
+ analytics: false,
+ realtime: false
+ };
+ }
+
+ /**
+ * Connect to vendor API
+ */
+ async connect() {
+ try {
+ // TODO: Implement your connection logic
+ // Example: await fetch(this.config.apiUrl + '/connect')
+
+ this.isConnected = true;
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ /**
+ * Get market data for a symbol
+ * Only implement if marketData capability is true
+ */
+ async getMarketData(symbol) {
+ try {
+ // TODO: Implement your market data API call
+ // Example:
+ // const response = await fetch(`${this.config.apiUrl}/market/${symbol}`);
+ // const data = await response.json();
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: 0,
+ change: 0,
+ volume: 0
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ /**
+ * Place an order
+ * Only implement if orderManagement capability is true
+ */
+ async placeOrder(orderData) {
+ try {
+ // TODO: Implement your order placement logic
+
+ return {
+ success: true,
+ orderId: '',
+ status: 'pending'
+ };
+ } catch (error) {
+ return this.handleError(error, 'placeOrder');
+ }
+ }
+
+ /**
+ * Get portfolio data
+ * Only implement if portfolio capability is true
+ */
+ async getPortfolio() {
+ try {
+ // TODO: Implement your portfolio API call
+
+ return {
+ success: true,
+ data: {
+ totalValue: 0,
+ positions: []
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getPortfolio');
+ }
+ }
+
+ /**
+ * Get analytics for a symbol
+ * Only implement if analytics capability is true
+ */
+ async getAnalytics(symbol) {
+ try {
+ // TODO: Implement your analytics API call
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ indicators: {}
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ /**
+ * Add any custom methods your vendor needs
+ */
+ async customMethod() {
+ try {
+ // Your custom implementation
+ return { success: true };
+ } catch (error) {
+ return this.handleError(error, 'customMethod');
+ }
+ }
+}
+
+export default VendorTemplate;
\ No newline at end of file
diff --git a/src/vendors/YFinanceVendor.js b/src/vendors/YFinanceVendor.js
new file mode 100644
index 000000000..963720653
--- /dev/null
+++ b/src/vendors/YFinanceVendor.js
@@ -0,0 +1,232 @@
+import { BaseVendorAdapter } from '../core/BaseVendorAdapter';
+
+class YFinanceVendor extends BaseVendorAdapter {
+ constructor(config = {}) {
+ super('Yahoo Finance', {
+ baseUrl: 'https://query1.finance.yahoo.com/v8/finance/chart/',
+ intervals: ['1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '1d', '5d', '1wk', '1mo', '3mo'],
+ ...config
+ });
+ this.cache = new Map();
+ this.cacheTimeout = 30000; // 30 seconds
+ }
+
+ getCapabilities() {
+ return {
+ marketData: true,
+ orderManagement: false,
+ portfolio: false,
+ analytics: true,
+ realtime: true
+ };
+ }
+
+ async connect() {
+ try {
+ // Test connection with a simple quote
+ const testResult = await this.getMarketData('AAPL');
+ this.isConnected = testResult.success;
+ return { success: this.isConnected };
+ } catch (error) {
+ return this.handleError(error, 'connect');
+ }
+ }
+
+ async getMarketData(symbol, interval = '1d') {
+ try {
+ const cacheKey = `${symbol}_${interval}`;
+ const cached = this.cache.get(cacheKey);
+
+ if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+ return { success: true, data: cached.data };
+ }
+
+ // Use Yahoo Finance API directly (simplified version of the Python script logic)
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=1d`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ const result = this.parseYahooResponse(data, symbol);
+
+ // Cache the result
+ this.cache.set(cacheKey, {
+ data: result,
+ timestamp: Date.now()
+ });
+
+ return { success: true, data: result };
+ } catch (error) {
+ return this.handleError(error, 'getMarketData');
+ }
+ }
+
+ async getHistoricalData(symbol, interval = '1d', period = '1mo') {
+ try {
+ const url = `${this.config.baseUrl}${symbol}?interval=${interval}&range=${period}`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return {
+ success: true,
+ data: this.parseHistoricalData(data, symbol)
+ };
+ } catch (error) {
+ return this.handleError(error, 'getHistoricalData');
+ }
+ }
+
+ async getAnalytics(symbol) {
+ try {
+ // Get multiple timeframes for analytics
+ const [daily, weekly] = await Promise.all([
+ this.getMarketData(symbol, '1d'),
+ this.getMarketData(symbol, '1wk')
+ ]);
+
+ if (!daily.success || !weekly.success) {
+ throw new Error('Failed to fetch data for analytics');
+ }
+
+ return {
+ success: true,
+ data: {
+ symbol,
+ price: daily.data.price,
+ change: daily.data.change,
+ changePercent: daily.data.changePercent,
+ volume: daily.data.volume,
+ marketCap: daily.data.marketCap,
+ pe: daily.data.pe,
+ weeklyTrend: weekly.data.change > 0 ? 'UP' : 'DOWN',
+ volatility: this.calculateVolatility(daily.data, weekly.data),
+ recommendation: this.generateRecommendation(daily.data)
+ }
+ };
+ } catch (error) {
+ return this.handleError(error, 'getAnalytics');
+ }
+ }
+
+ parseYahooResponse(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid response format');
+ }
+
+ const meta = chart.meta;
+ const quote = chart.indicators?.quote?.[0];
+
+ return {
+ symbol,
+ price: meta.regularMarketPrice || 0,
+ change: (meta.regularMarketPrice - meta.previousClose) || 0,
+ changePercent: ((meta.regularMarketPrice - meta.previousClose) / meta.previousClose * 100) || 0,
+ volume: meta.regularMarketVolume || 0,
+ marketCap: meta.marketCap || null,
+ pe: meta.trailingPE || null,
+ high: quote?.high?.[quote.high.length - 1] || meta.regularMarketDayHigh,
+ low: quote?.low?.[quote.low.length - 1] || meta.regularMarketDayLow,
+ open: quote?.open?.[0] || meta.regularMarketDayLow,
+ previousClose: meta.previousClose || 0,
+ timestamp: Date.now()
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse Yahoo response: ${error.message}`);
+ }
+ }
+
+ parseHistoricalData(data, symbol) {
+ try {
+ const chart = data.chart?.result?.[0];
+ if (!chart) {
+ throw new Error('Invalid historical data format');
+ }
+
+ const timestamps = chart.timestamp || [];
+ const quote = chart.indicators?.quote?.[0] || {};
+
+ return {
+ symbol,
+ data: timestamps.map((ts, i) => ({
+ timestamp: new Date(ts * 1000).toISOString(),
+ open: quote.open?.[i] || null,
+ high: quote.high?.[i] || null,
+ low: quote.low?.[i] || null,
+ close: quote.close?.[i] || null,
+ volume: quote.volume?.[i] || null
+ })).filter(item => item.close !== null)
+ };
+ } catch (error) {
+ throw new Error(`Failed to parse historical data: ${error.message}`);
+ }
+ }
+
+ calculateVolatility(dailyData, weeklyData) {
+ // Simple volatility calculation
+ const dailyChange = Math.abs(dailyData.changePercent || 0);
+ const weeklyChange = Math.abs(weeklyData.changePercent || 0);
+
+ if (dailyChange > 5 || weeklyChange > 15) return 'HIGH';
+ if (dailyChange > 2 || weeklyChange > 8) return 'MEDIUM';
+ return 'LOW';
+ }
+
+ generateRecommendation(data) {
+ const { changePercent, volume, pe } = data;
+
+ let score = 0;
+ if (changePercent > 2) score += 1;
+ if (changePercent < -2) score -= 1;
+ if (volume > 1000000) score += 0.5;
+ if (pe && pe < 15) score += 0.5;
+ if (pe && pe > 30) score -= 0.5;
+
+ if (score > 1) return 'BUY';
+ if (score < -1) return 'SELL';
+ return 'HOLD';
+ }
+
+ // Bulk download method (adapted from Python script)
+ async bulkDownload(symbols, intervals = ['1d'], options = {}) {
+ try {
+ const results = {};
+ const batchSize = options.batchSize || 10;
+
+ for (let i = 0; i < symbols.length; i += batchSize) {
+ const batch = symbols.slice(i, i + batchSize);
+
+ for (const symbol of batch) {
+ for (const interval of intervals) {
+ try {
+ const data = await this.getHistoricalData(symbol, interval, options.period || '1mo');
+ if (!results[symbol]) results[symbol] = {};
+ results[symbol][interval] = data;
+ } catch (error) {
+ console.warn(`Failed to download ${symbol} ${interval}:`, error);
+ }
+ }
+ }
+
+ // Rate limiting (like the Python script)
+ if (i + batchSize < symbols.length) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+ }
+
+ return { success: true, data: results };
+ } catch (error) {
+ return this.handleError(error, 'bulkDownload');
+ }
+ }
+}
+
+export default YFinanceVendor;
\ No newline at end of file