From f5d0051a195776ca6e300c013a2516afc4eafc93 Mon Sep 17 00:00:00 2001 From: Cesar Mendivil Date: Sun, 16 Nov 2025 21:47:47 -0700 Subject: [PATCH] feat: add form components including Checkbox, Radio, Switch, and Textarea --- .env.production.local | 5 + .github/workflows/e2e-playwright.yml | 59 + DEPLOY_PROD.md | 72 + deploy/avanzacast-stack.service | 16 + deploy/deploy_prod.sh | 91 + docker-compose.prod.yml | 80 + docker/local-nginx/docker-compose.yml | 12 + docker/local-nginx/nginx.conf | 72 + docker/nginx/default.conf | 39 + docs/img.png | Bin 0 -> 35436 bytes docs/img_1.png | Bin 0 -> 190912 bytes docs/img_2.png | Bin 0 -> 31113 bytes docs/screenshot_streamyard.png | Bin 149290 -> 104196 bytes package-lock.json | 2729 ++++++++++++++++- package.json | 2 +- packages/avanza-ui/README.md | 230 +- .../avanza-ui/src/components/ControlBar.tsx | 21 + .../src/components/ControlGroup.module.css | 16 + .../avanza-ui/src/components/ControlGroup.tsx | 21 + .../src/components/IconButton.module.css | 21 + .../avanza-ui/src/components/IconButton.tsx | 38 + .../src/components/StudioHeader.module.css | 44 +- .../src/components/VideoTile.module.css | 82 +- packages/avanza-ui/src/index.ts | 11 +- packages/avanza-ui/src/styles/controls.css | 108 + packages/avanza-ui/src/styles/globals.css | 154 + .../avanza-ui/src/styles/studio-theme.css | 225 +- packages/backend-api/.env.production | 15 + packages/backend-api/Dockerfile | 28 + packages/backend-api/build_and_run_backend.sh | 26 + packages/backend-api/package.json | 2 +- packages/backend-api/src/index.ts | 340 +- packages/broadcast-panel/Dockerfile | 23 +- packages/broadcast-panel/README.md | 25 + .../broadcast-panel/public/dump_session.html | 15 + .../public/post_token_to_studio.html | 133 + .../broadcast-panel/scripts/simulate_ack.js | 0 .../broadcast-panel/src/components/Toast.tsx | 20 + .../src/components/TransmissionsTable.tsx | 80 +- .../src/hooks/useStudioLauncher.ts | 178 ++ .../broadcast-panel/src/hooks/useToast.tsx | 44 + packages/broadcast-panel/src/main.tsx | 7 +- .../src/utils/studioLauncher.ts | 100 + packages/landing-page/postcss.config.cjs | 20 +- packages/studio-panel/.dockerignore | 9 + packages/studio-panel/Dockerfile | 28 + packages/studio-panel/README.DOCKER.md | 70 + packages/studio-panel/README.E2E.md | 34 + .../studio-panel/build_and_pack_docker.sh | 36 + .../studio-panel/deploy/nginx.avanzacast.conf | 53 + .../studio-panel/deploy/studio-panel.service | 16 + .../studio-panel/e2e/playwright.config.js | 6 + packages/studio-panel/e2e/playwright_test.mjs | 81 + packages/studio-panel/e2e/run_e2e.mjs | 147 + .../e2e/selectors_streamyard.json | 103 + packages/studio-panel/e2e/server.mjs | 42 + packages/studio-panel/e2e/simulated_flow.mjs | 95 + packages/studio-panel/e2e/static/sender.html | 48 + packages/studio-panel/e2e/static/studio.html | 38 + .../e2e/tests/postMessage.e2e.spec.js | 51 + packages/studio-panel/index.html | 38 +- packages/studio-panel/package.json | 47 +- packages/studio-panel/playwright.config.ts | 19 + packages/studio-panel/postcss.config.cjs | 12 +- .../studio-panel/public/debug-styles.html | 79 + .../public/simulate_postmessage.html | 154 + .../studio-panel/public/studio_receiver.html | 70 + packages/studio-panel/run_e2e_session.sh | 42 + packages/studio-panel/run_playwright_test.sh | 58 + .../scripts/check_styles_playwright.mjs | 28 + .../scripts/check_styles_playwright_3021.mjs | 29 + .../scripts/e2e_portal_interaction.mjs | 31 + .../scripts/e2e_session_http_runner.mjs | 59 + .../scripts/e2e_session_runner.mjs | 103 + .../scripts/e2e_simulate_guests.mjs | 164 + .../scripts/playwright_mcp_flow.mjs | 285 ++ .../scripts/playwright_postmessage_test.mjs | 152 + .../scripts/playwright_rec_test.mjs | 34 + .../studio-panel/scripts/pp_screenshot.mjs | 14 + packages/studio-panel/src/App.tsx | 174 +- .../src/__tests__/StudioPortal.test.tsx | 61 + .../src/__tests__/postMessage.test.ts | 37 + .../studio-panel/src/__tests__/smoke.test.tsx | 39 + .../src/components/BottomControls.tsx | 180 +- .../studio-panel/src/components/ChatPanel.tsx | 8 +- .../src/components/LivekitConnector.tsx | 365 ++- .../src/components/Portal/StudioPortal.css | 16 + .../src/components/Portal/StudioPortal.tsx | 171 ++ .../src/components/StudioRoom/StudioRoom.css | 88 + .../src/components/StudioRoom/StudioRoom.tsx | 244 +- packages/studio-panel/src/main.tsx | 107 +- packages/studio-panel/src/styles.css | 9 +- .../src/styles/avanza-utilities.css | 272 ++ .../studio-panel/src/utils/postMessage.ts | 39 + .../tests/e2e/session_flow.spec.ts | 70 + packages/studio-panel/vite.config.ts | 23 +- packages/studio-panel/vitest.config.ts | 16 + scripts/check_cors.sh | 71 + scripts/restart_backend_prod.sh | 83 + scripts/smoke_studio_session.sh | 34 + 100 files changed, 8861 insertions(+), 725 deletions(-) create mode 100644 .env.production.local create mode 100644 .github/workflows/e2e-playwright.yml create mode 100644 DEPLOY_PROD.md create mode 100644 deploy/avanzacast-stack.service create mode 100644 deploy/deploy_prod.sh create mode 100644 docker-compose.prod.yml create mode 100644 docker/local-nginx/docker-compose.yml create mode 100644 docker/local-nginx/nginx.conf create mode 100644 docker/nginx/default.conf create mode 100644 docs/img.png create mode 100644 docs/img_1.png create mode 100644 docs/img_2.png create mode 100644 packages/avanza-ui/src/components/ControlBar.tsx create mode 100644 packages/avanza-ui/src/components/ControlGroup.module.css create mode 100644 packages/avanza-ui/src/components/ControlGroup.tsx create mode 100644 packages/avanza-ui/src/components/IconButton.module.css create mode 100644 packages/avanza-ui/src/components/IconButton.tsx create mode 100644 packages/avanza-ui/src/styles/controls.css create mode 100644 packages/backend-api/.env.production create mode 100644 packages/backend-api/Dockerfile create mode 100755 packages/backend-api/build_and_run_backend.sh create mode 100644 packages/broadcast-panel/public/dump_session.html create mode 100644 packages/broadcast-panel/public/post_token_to_studio.html create mode 100644 packages/broadcast-panel/scripts/simulate_ack.js create mode 100644 packages/broadcast-panel/src/components/Toast.tsx create mode 100644 packages/broadcast-panel/src/hooks/useStudioLauncher.ts create mode 100644 packages/broadcast-panel/src/hooks/useToast.tsx create mode 100644 packages/broadcast-panel/src/utils/studioLauncher.ts create mode 100644 packages/studio-panel/.dockerignore create mode 100644 packages/studio-panel/Dockerfile create mode 100644 packages/studio-panel/README.DOCKER.md create mode 100644 packages/studio-panel/README.E2E.md create mode 100755 packages/studio-panel/build_and_pack_docker.sh create mode 100644 packages/studio-panel/deploy/nginx.avanzacast.conf create mode 100644 packages/studio-panel/deploy/studio-panel.service create mode 100644 packages/studio-panel/e2e/playwright.config.js create mode 100644 packages/studio-panel/e2e/playwright_test.mjs create mode 100644 packages/studio-panel/e2e/run_e2e.mjs create mode 100644 packages/studio-panel/e2e/selectors_streamyard.json create mode 100644 packages/studio-panel/e2e/server.mjs create mode 100644 packages/studio-panel/e2e/simulated_flow.mjs create mode 100644 packages/studio-panel/e2e/static/sender.html create mode 100644 packages/studio-panel/e2e/static/studio.html create mode 100644 packages/studio-panel/e2e/tests/postMessage.e2e.spec.js create mode 100644 packages/studio-panel/playwright.config.ts create mode 100644 packages/studio-panel/public/debug-styles.html create mode 100644 packages/studio-panel/public/simulate_postmessage.html create mode 100644 packages/studio-panel/public/studio_receiver.html create mode 100755 packages/studio-panel/run_e2e_session.sh create mode 100755 packages/studio-panel/run_playwright_test.sh create mode 100644 packages/studio-panel/scripts/check_styles_playwright.mjs create mode 100644 packages/studio-panel/scripts/check_styles_playwright_3021.mjs create mode 100644 packages/studio-panel/scripts/e2e_portal_interaction.mjs create mode 100644 packages/studio-panel/scripts/e2e_session_http_runner.mjs create mode 100644 packages/studio-panel/scripts/e2e_session_runner.mjs create mode 100644 packages/studio-panel/scripts/e2e_simulate_guests.mjs create mode 100644 packages/studio-panel/scripts/playwright_mcp_flow.mjs create mode 100644 packages/studio-panel/scripts/playwright_postmessage_test.mjs create mode 100644 packages/studio-panel/scripts/playwright_rec_test.mjs create mode 100644 packages/studio-panel/scripts/pp_screenshot.mjs create mode 100644 packages/studio-panel/src/__tests__/StudioPortal.test.tsx create mode 100644 packages/studio-panel/src/__tests__/postMessage.test.ts create mode 100644 packages/studio-panel/src/__tests__/smoke.test.tsx create mode 100644 packages/studio-panel/src/components/Portal/StudioPortal.css create mode 100644 packages/studio-panel/src/components/Portal/StudioPortal.tsx create mode 100644 packages/studio-panel/src/styles/avanza-utilities.css create mode 100644 packages/studio-panel/src/utils/postMessage.ts create mode 100644 packages/studio-panel/tests/e2e/session_flow.spec.ts create mode 100644 packages/studio-panel/vitest.config.ts create mode 100755 scripts/check_cors.sh create mode 100755 scripts/restart_backend_prod.sh create mode 100755 scripts/smoke_studio_session.sh diff --git a/.env.production.local b/.env.production.local new file mode 100644 index 0000000..524bbc1 --- /dev/null +++ b/.env.production.local @@ -0,0 +1,5 @@ +# Top-level production environment pointers for local testing (do not commit secrets) +VITE_STUDIO_URL=https://avanzacast-studio.bfzqqk.easypanel.host +VITE_BROADCASTPANEL_URL=https://avanzacast-broadcastpanel.bfzqqk.easypanel.host +VITE_TOKEN_SERVER_URL=https://avanzacast-servertokens.bfzqqk.easypanel.host + diff --git a/.github/workflows/e2e-playwright.yml b/.github/workflows/e2e-playwright.yml new file mode 100644 index 0000000..836d94e --- /dev/null +++ b/.github/workflows/e2e-playwright.yml @@ -0,0 +1,59 @@ +name: E2E Playwright - Studio Panel + +on: + workflow_dispatch: {} + push: + paths: + - 'packages/studio-panel/**' + +jobs: + playwright-e2e: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies for studio-panel + working-directory: packages/studio-panel + run: | + npm ci + + - name: Install Playwright browsers + working-directory: packages/studio-panel + run: | + npx playwright install --with-deps + + - name: Run Playwright E2E script + working-directory: packages/studio-panel + env: + # override the URLs here if you want to use different targets in CI + BROADCAST_URL: ${{ secrets.BROADCAST_URL }} + STUDIO_ORIGIN: ${{ secrets.STUDIO_ORIGIN }} + run: | + node --experimental-vm-modules scripts/playwright_postmessage_test.mjs + + - name: Upload Playwright debug log + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-debug-log + path: | + /tmp/playwright_debug.log + /tmp/playwright_run_output.log + /tmp/sim_postmessage_simulator.png + /tmp/sim_postmessage_studio.png + + - name: Print small summary + if: always() + working-directory: packages/studio-panel + run: | + echo "Artifacts uploaded: /tmp/playwright_debug.log, /tmp/playwright_run_output.log, screenshots" + ls -lh /tmp/playwright_debug.log /tmp/playwright_run_output.log || true + ls -lh /tmp/sim_postmessage_simulator.png /tmp/sim_postmessage_studio.png || true + diff --git a/DEPLOY_PROD.md b/DEPLOY_PROD.md new file mode 100644 index 0000000..b51f79a --- /dev/null +++ b/DEPLOY_PROD.md @@ -0,0 +1,72 @@ +# AvanzaCast - Production Deployment (Docker Compose) + +This file shows how to build and run the production stack locally (or on a server) with Docker Compose. It sets up: +- `backend-api` (token server) on port 4000 +- `studio-panel` served by nginx on port 80 inside container +- `broadcast-panel` on port 5175 +- `reverse-proxy` (nginx) mapping the three domains to containers + +Prerequisites +- Docker and docker-compose installed on the host +- DNS or hosts entries mapping the following hostnames to the server IP: + - `avanzacast-broadcastpanel.bfzqqk.easypanel.host` + - `avanzacast-studio.bfzqqk.easypanel.host` + - `avanzacast-servertokens.bfzqqk.easypanel.host` +- TLS/SSL: this example doesn't include certificates. Use a separate step with Certbot / Let's Encrypt or your load balancer to provide SSL. Do NOT expose token server over plain HTTP in production without TLS. + +Files created +- `docker-compose.prod.yml` - compose file to build and run the stack +- `docker/nginx/default.conf` - nginx config for reverse proxy +- `packages/backend-api/.env.production` - production environment variables for backend-api (placeholder) + +Build & Run + +1. Build and start the stack + +```bash +# from repo root +docker compose -f docker-compose.prod.yml up --build -d + +# check status +docker compose -f docker-compose.prod.yml ps +``` + +2. Verify backend health and CORS + +```bash +# verify backend health +curl -i http://localhost:4000/health + +# simulate the broadcast requesting token +curl -i -H "Origin: https://avanzacast-broadcastpanel.bfzqqk.easypanel.host" \ + "http://localhost:4000/api/token?room=studio-demo&username=simulator" +``` + +You should see an `Access-Control-Allow-Origin` header in the response. If it returns 500 with `LiveKit credentials not configured`, add real `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` to `packages/backend-api/.env.production` and restart. + +3. Verify the UIs + +Open in browser (or use Playwright): +- https://avanzacast-broadcastpanel.bfzqqk.easypanel.host +- https://avanzacast-studio.bfzqqk.easypanel.host + +4. Run E2E test locally (Playwright) + +```bash +cd packages/studio-panel +chmod +x run_playwright_test.sh +./run_playwright_test.sh + +# artifacts will be in /tmp: +ls -lh /tmp/playwright_debug.log /tmp/playwright_run_output.log /tmp/sim_postmessage_simulator.png /tmp/sim_postmessage_studio.png +``` + +Troubleshooting +- If CORS is blocked: edit `packages/backend-api/src/index.ts` and ensure allowed origins include your domains, then rebuild/restart. +- If the backend dies with EBADF or IO errors: run `npx tsx src/index.ts` in foreground to get full stack trace, paste here. +- For TLS termination: configure nginx with certificates or put the stack behind a TLS-enabled LB. + +Security +- Do not commit real secrets to the repo. Use environment variables or a secret manager. The `.env.production` file created contains placeholders; replace with real values on the server. + + diff --git a/deploy/avanzacast-stack.service b/deploy/avanzacast-stack.service new file mode 100644 index 0000000..02e3ee6 --- /dev/null +++ b/deploy/avanzacast-stack.service @@ -0,0 +1,16 @@ +[Unit] +Description=AvanzaCast Docker Compose Stack +After=docker.service +Requires=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/home/xesar/Documentos/Nextream/AvanzaCast +ExecStart=/usr/bin/docker compose -f /home/xesar/Documentos/Nextream/AvanzaCast/docker-compose.prod.yml up -d --build +ExecStop=/usr/bin/docker compose -f /home/xesar/Documentos/Nextream/AvanzaCast/docker-compose.prod.yml down +TimeoutStartSec=600 + +[Install] +WantedBy=multi-user.target + diff --git a/deploy/deploy_prod.sh b/deploy/deploy_prod.sh new file mode 100644 index 0000000..b05e0d5 --- /dev/null +++ b/deploy/deploy_prod.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +COMPOSE_FILE="$REPO_ROOT/docker-compose.prod.yml" +SERVICE_UNIT="/etc/systemd/system/avanzacast-stack.service" +LOCAL_UNIT_FILE="$REPO_ROOT/deploy/avanzacast-stack.service" + +usage() { + cat </dev/null 2>&1; then + echo "docker not found; please install Docker on this host" >&2 + exit 1 + fi +} + +build_images() { + echo "[deploy] Building images with docker compose..." + docker compose -f "$COMPOSE_FILE" build --pull +} + +compose_up() { + echo "[deploy] Bringing up compose stack..." + docker compose -f "$COMPOSE_FILE" up -d --build +} + +compose_down() { + echo "[deploy] Bringing down compose stack..." + docker compose -f "$COMPOSE_FILE" down +} + +install_unit() { + if [ ! -f "$LOCAL_UNIT_FILE" ]; then + echo "unit file $LOCAL_UNIT_FILE not found" >&2 + exit 1 + fi + echo "[deploy] Installing systemd unit to $SERVICE_UNIT (requires sudo)" + sudo cp "$LOCAL_UNIT_FILE" "$SERVICE_UNIT" + sudo systemctl daemon-reload +} + +enable_start_unit() { + echo "[deploy] Enabling and starting avanzacast-stack.service" + sudo systemctl enable --now avancacast-stack.service +} + +remove_unit() { + echo "[deploy] Stopping and removing avanzacast-stack.service" + sudo systemctl stop avancacast-stack.service || true + sudo systemctl disable avancacast-stack.service || true + sudo rm -f "$SERVICE_UNIT" + sudo systemctl daemon-reload +} + +while [ "$#" -gt 0 ]; do + case "$1" in + --build-only) ensure_docker; build_images; shift ;; + --up) ensure_docker; compose_up; shift ;; + --down) ensure_docker; compose_down; shift ;; + --install-unit) install_unit; shift ;; + --enable-start) enable_start_unit; shift ;; + --remove-unit) remove_unit; shift ;; + --help) usage; exit 0 ;; + *) echo "Unknown option: $1" >&2; usage; exit 1 ;; + esac +done + diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..d7cc13a --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,80 @@ +version: '3.8' + +services: + backend-api: + build: + context: ./packages/backend-api + dockerfile: Dockerfile + env_file: + - ./packages/backend-api/.env.production + environment: + - REDIS_URL=redis://redis:6379 + restart: unless-stopped + networks: + - webnet + expose: + - "4000" + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:4000/health || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + + studio-panel: + build: + context: . + dockerfile: ./packages/studio-panel/Dockerfile.simple + environment: + - VITE_TOKEN_SERVER_URL=http://backend-api:4000 + - VITE_STUDIO_URL=https://avanzacast-studio.bfzqqk.easypanel.host + - VITE_BROADCASTPANEL_URL=https://avanzacast-broadcastpanel.bfzqqk.easypanel.host + restart: unless-stopped + networks: + - webnet + expose: + - "80" + volumes: + - ./docker/letsencrypt:/etc/letsencrypt:ro + + broadcast-panel: + build: + context: ./packages/broadcast-panel + dockerfile: Dockerfile + environment: + - VITE_TOKEN_SERVER_URL=http://backend-api:4000 + - VITE_BROADCASTPANEL_URL=https://avanzacast-broadcastpanel.bfzqqk.easypanel.host + restart: unless-stopped + networks: + - webnet + expose: + - "5175" + volumes: + - ./docker/letsencrypt:/etc/letsencrypt:ro + + redis: + image: redis:7-alpine + restart: unless-stopped + networks: + - webnet + expose: + - "6379" + + reverse-proxy: + image: nginx:stable-alpine + volumes: + - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + - ./docker/letsencrypt:/etc/letsencrypt:ro + ports: + - "80:80" + - "443:443" + depends_on: + - backend-api + - studio-panel + - broadcast-panel + networks: + - webnet + restart: unless-stopped + +networks: + webnet: + driver: bridge diff --git a/docker/local-nginx/docker-compose.yml b/docker/local-nginx/docker-compose.yml new file mode 100644 index 0000000..c1a96ef --- /dev/null +++ b/docker/local-nginx/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' +services: + nginx: + image: nginx:1.21-alpine + container_name: avz_local_nginx + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + network_mode: host + restart: unless-stopped + environment: + - NGINX_HOST=local + diff --git a/docker/local-nginx/nginx.conf b/docker/local-nginx/nginx.conf new file mode 100644 index 0000000..fed68db --- /dev/null +++ b/docker/local-nginx/nginx.conf @@ -0,0 +1,72 @@ +# nginx config to proxy production hostnames to local dev servers +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + + upstream broadcast_panel { + server 127.0.0.1:5175; + } + + upstream studio_panel { + server 127.0.0.1:3020; + } + + upstream token_server { + server 127.0.0.1:4000; + } + + server { + listen 80; + server_name avanzacast-broadcastpanel.bfzqqk.easypanel.host; + + location / { + proxy_pass http://broadcast_panel; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + + server { + listen 80; + server_name avanzacast-studio.bfzqqk.easypanel.host; + + location / { + proxy_pass http://studio_panel; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + + server { + listen 80; + server_name avanzacast-servertokens.bfzqqk.easypanel.host; + + location / { + proxy_pass http://token_server; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + + # optional: default catch-all to show a basic message + server { + listen 80 default_server; + server_name _; + return 200 'AvanzaCast local proxy running.'; + } +} + diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf new file mode 100644 index 0000000..8b3f3b4 --- /dev/null +++ b/docker/nginx/default.conf @@ -0,0 +1,39 @@ +server { + listen 80; + server_name avanzacast-broadcastpanel.bfzqqk.easypanel.host; + + location / { + proxy_pass http://broadcast-panel:5175; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +server { + listen 80; + server_name avanzacast-studio.bfzqqk.easypanel.host; + + location / { + proxy_pass http://studio-panel:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +server { + listen 80; + server_name avanzacast-servertokens.bfzqqk.easypanel.host; + + location / { + proxy_pass http://backend-api:4000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + diff --git a/docs/img.png b/docs/img.png new file mode 100644 index 0000000000000000000000000000000000000000..db422c5dbfdceefa54e505ced99cad969529dc61 GIT binary patch literal 35436 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 Mq@qNrn4#Z)1CvwI)Bpeg literal 0 HcmV?d00001 diff --git a/docs/img_1.png b/docs/img_1.png new file mode 100644 index 0000000000000000000000000000000000000000..3011a450f01862afbcf9b7cef0d243143953aeb3 GIT binary patch literal 190912 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%0Acs%LVKP2Iyr8@0N6hoMmsh-lJf>MV#J2 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�sZnDYhi#G3W|eyd=|)o*U8n>ffD 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

vCav`my<90|Ak0TOb#xwUV(`&Yt{4K;7g82 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

p>oQW)JP zVNI}Cc2-dck+eQr9>j90Z;gmJrFp9fjygQ{v#q3F0SY5lC=VaTM{DcQ(aSkMc#;em z@9XP36G|qv=i7*a7OI^oF-t*c%ELwo@-wK8tMh#YK)S-Y!-My3^51UdYJIjXkDOua z^LugMZF8?hafVKoS>pMwd4?i~WLsxYsvBzXeyqjD9jM)f%h6K@FcrOX!u!NJUxLn# z!0G8$Ik~U)fAyB{a0=F6$h%9kn~OyLJe$gA;5@LIJa>fq6oo6lAlJMyZJaO3evdB0 z{J7n9v1ZdX<|_LIv38Eynrm*^f9cd{=F@9}tb<@!;vS%BqZwiCRpJy+Vy}a8Ifd5_zMc7OlzD z|9nZz-(FV-`TpGLX?LdHLONZrb%~E9MHj5SvMp!VutwhYJjLP31+Dk9J@wXuk+b&v z7ihvXD55w+LBwtL67xTn^m$*IgLfN8(;oY>>9d}}V|v0)EN3Y{4B+3qo@+F1A7Hh$ z%Xw4@c|5t&``r8B#(4Y4gS@#s*r^LSDYVYuZWBm9@= zE+p0xpw0YiIaQ~(xP9?aKSujmD&k2&;}KG)u|DliO58wk(nZfkUecm^%f$hvb?@li z@IA!JR8`tFnC90nR%(kD6DSe+iJ9=?2+GRV8Q zFS7B^FwNNp@mYj3UOzKe*hWCH+K1`pi1b=M&#(W$_r7Q*XvV-W$Njp(tK$l>VHDZS zkjs5swBIwBTK(CD6v=C8I=`diW*;<9w1M}U!$Xk_>0bqRJf<8b@sY-OJb)F1qU@kh z$we8dUtw%$VUz`U^d-skt zFEOJdM{eps*`OG{!>Y_<`f7fs8mwz(*TmfL=drn}p08o|V)3pzaxFrO4#=acHT6Gf z<;L_mjC`o%71c)7%pD<1cA$C|B^Fv1Nm%eFR1r%HUmspnQxkucZE0vY;bl6fv?t(C zCEo6s=@X>qxBB4s^tdIdTT{EUU(|3T;Y(G`zVTH_fEPWC+hlxsX|Mh_(1%ujLGQ)s zZ*yCgs9-hQ>e+P8&aJo(h|4>;>c227Ks|#s!;Frvc~f8KQCv*vbo-t--JaRlJ4*}r z)Y8-e72#x9eamP_-JtH-KOFCSxaUivOHQ8BfWGZ1ifvL3k3hPq@ZN|`ipdram9mhm z6+2xPMNP?da%}j@dfi0PSC0;&X68~fLS_EFTB!`_V0O1=W4t-;!-9O^Q1oi(1?|L5 zr;&c6CR13-h_YW{H-HhaFq&s*o7F8lnzB0@qa3RWS@6G>f;m&8KqJ6B1!^|E?+nNq zcf*g=RvV(c6OO(9D(?OHx=ReGzysLgEzW6>Y=^(gBeu9zu&2 z7_0@3VRkJD6DlAyfG6C4z%g{F}e^2TJrRY7Do0ub4XV3IZ_O>;X7?(mNIEMpo_LQN_Jt&R*YDoW0XEgq}D6T+(?8X8Zpo zfXu6^?tmv_w^1o?f3}!%|6LyD+X`LTb<*+pce0zS;u}J4VFNpw_v_k9LtjMqR9#G# z<~<|YbY`b5@)hiay_pzYn{VTqHUbr)(4>{HZPbX{)4X4`%-HE+qC{Wu20+0QW>e2zi<_x36G}rKM%Jw4TjP;+ra2SJr7)D&*c#k2b;KE<;!2o3dIIWmnW` z5AuRpTS{ILYT6Of)ENGqwS?u(zkah`tfxly6j>le48)U++@xBxqpi=4fztJ40lpUJ zOyHQ~v}lFOXMeW0wbfmQpM!(PJ2o^!KQazZnN+UqN0E;ySKt>$BFFoOh6IvvbBbA0 zx}R=LrewjaB$^bEmJEq5Cv0JbOF#%dAOBYp#mEj-K3T?RdgGc|%JgWe`&|^)bgsfK zEr(unbg&QL$lHAD9J))Zdsk#u7<%8~gq2KYYYj7d7k2z}KUsI|#l&__ zK0n^tdj32!L~jW`n@-faKom+B0!34ueNbXW)+}$(g2x|RcHPN`yUSoF&d*Xx}wiu?JT&&M0H(M1!3d5gM(-*#{BTW z(2YnX*~pPq*G?MGtSf{dy>KF&u;UC14iJfr@-te4jG5T-I(+RcxV`vG>vz6%5Yz eJ;#su{xfmbuJ34Hvm*O9dM1Wu26=FY!2bg2j2$Zg literal 0 HcmV?d00001 diff --git a/docs/img_2.png b/docs/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..3da46484155dad31e1d0a2418b2ab996aa5b4475 GIT binary patch literal 31113 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 diff --git a/package-lock.json b/package-lock.json index 2fffdad..02c53c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ }, "devDependencies": { "concurrently": "^8.2.2", - "playwright": "^1.38.0", + "playwright": "^1.51.0", "typescript": "^5.2.2" }, "engines": { @@ -3929,6 +3929,40 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.5.0.tgz", + "integrity": "sha512-qYDdL7fPwLRI+bJNurVcis+tNgJmvWjH4YTBGXTA8xMuxFrnAz6E5o35iyzyKbq5J5Lr8mJGfrR5GXl+WGwhgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "magic-string": "^0.27.0", + "react-docgen-typescript": "^2.2.2" + }, + "peerDependencies": { + "typescript": ">= 4.3.x", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -4119,6 +4153,24 @@ "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.4.47.tgz", "integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==" }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -4307,6 +4359,7 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4320,6 +4373,7 @@ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "playwright-core": "1.56.1" }, @@ -4338,6 +4392,7 @@ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "dev": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -5541,6 +5596,947 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, + "node_modules/@storybook/addon-actions": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.6.14.tgz", + "integrity": "sha512-mDQxylxGGCQSK7tJPkD144J8jWh9IU9ziJMHfB84PKpI/V5ZgqMDnpr2bssTrUaGDqU5e1/z8KcRF+Melhs9pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.6.14.tgz", + "integrity": "sha512-l9xS8qWe5n4tvMwth09QxH2PmJbCctEvBAc1tjjRasAfrd69f7/uFK4WhwJAstzBTNgTc8VXI4w8ZR97i1sFbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.6.14.tgz", + "integrity": "sha512-IiQpkNJdiRyA4Mq9mzjZlvQugL/aE7hNgVxBBGPiIZG6wb6Ht9hNnBYpap5ZXXFKV9p2qVI0FZK445ONmAa+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "dequal": "^2.0.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.14.tgz", + "integrity": "sha512-Obpd0OhAF99JyU5pp5ci17YmpcQtMNgqW2pTXV8jAiiipWpwO++hNDeQmLmlSXB399XjtRDOcDVkoc7rc6JzdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.6.14", + "@storybook/csf-plugin": "8.6.14", + "@storybook/react-dom-shim": "8.6.14", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.6.14.tgz", + "integrity": "sha512-5ZZSHNaW9mXMOFkoPyc3QkoNGdJHETZydI62/OASR0lmPlJ1065TNigEo5dJddmZNn0/3bkE8eKMAzLnO5eIdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/addon-actions": "8.6.14", + "@storybook/addon-backgrounds": "8.6.14", + "@storybook/addon-controls": "8.6.14", + "@storybook/addon-docs": "8.6.14", + "@storybook/addon-highlight": "8.6.14", + "@storybook/addon-measure": "8.6.14", + "@storybook/addon-outline": "8.6.14", + "@storybook/addon-toolbars": "8.6.14", + "@storybook/addon-viewport": "8.6.14", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.6.14.tgz", + "integrity": "sha512-4H19OJlapkofiE9tM6K/vsepf4ir9jMm9T+zw5L85blJZxhKZIbJ6FO0TCG9PDc4iPt3L6+aq5B0X29s9zicNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.6.14.tgz", + "integrity": "sha512-8VmElhm2XOjh22l/dO4UmXxNOolGhNiSpBcls2pqWSraVh4a670EyYBZsHpkXqfNHo2YgKyZN3C91+9zfH79qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.6.14", + "@storybook/test": "8.6.14", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-links": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.6.14.tgz", + "integrity": "sha512-DRlXHIyZzOruAZkxmXfVgTF+4d6K27pFcH4cUsm3KT1AXuZbr23lb5iZHpUZoG6lmU85Sru4xCEgewSTXBIe1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.6.14.tgz", + "integrity": "sha512-1Tlyb72NX8aAqm6I6OICsUuGOP6hgnXcuFlXucyhKomPa6j3Eu2vKu561t/f0oGtAK2nO93Z70kVaEh5X+vaGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.6.14.tgz", + "integrity": "sha512-CW857JvN6OxGWElqjlzJO2S69DHf+xO3WsEfT5mT3ZtIjmsvRDukdWfDU9bIYUFyA2lFvYjncBGjbK+I91XR7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.6.14.tgz", + "integrity": "sha512-W/wEXT8h3VyZTVfWK/84BAcjAxTdtRiAkT2KAN0nbSHxxB5KEM1MjKpKu2upyzzMa3EywITqbfy4dP6lpkVTwQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.6.14.tgz", + "integrity": "sha512-gNzVQbMqRC+/4uQTPI2ZrWuRHGquTMZpdgB9DrD88VTEjNudP+J6r8myLfr2VvGksBbUMHkGHMXHuIhrBEnXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.6.14.tgz", + "integrity": "sha512-rBMHAfA39AGHgkrDze4RmsnQTMw1ND5fGWobr9pDcJdnDKWQWNRD7Nrlxj0gFlN3n4D9lEZhWGdFrCbku7FVAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/icons": "^1.2.12", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^8.6.14" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-vite": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-8.6.14.tgz", + "integrity": "sha512-ajWYhy32ksBWxwWHrjwZzyC0Ii5ZTeu5lsqA95Q/EQBB0P5qWlHWGM3AVyv82Mz/ND03ebGy123uVwgf6olnYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf-plugin": "8.6.14", + "browser-assert": "^1.2.1", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/@storybook/components": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-8.6.14.tgz", + "integrity": "sha512-HNR2mC5I4Z5ek8kTrVZlIY/B8gJGs5b3XdZPBPBopTIN6U/YHXiDyOjY3JlaS4fSG1fVhp/Qp1TpMn1w/9m1pw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/core": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.6.14.tgz", + "integrity": "sha512-1P/w4FSNRqP8j3JQBOi3yGt8PVOgSRbP66Ok520T78eJBeqx9ukCfl912PQZ7SPbW3TIunBwLXMZOjZwBB/JmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/theming": "8.6.14", + "better-opn": "^3.0.2", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "esbuild-register": "^3.5.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "process": "^0.11.10", + "recast": "^0.23.5", + "semver": "^7.6.2", + "util": "^0.12.5", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/@storybook/core/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.6.14.tgz", + "integrity": "sha512-dErtc9teAuN+eelN8FojzFE635xlq9cNGGGEu0WEmMUQ4iJ8pingvBO1N8X3scz4Ry7KnxX++NNf3J3gpxS8qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.6.0.tgz", + "integrity": "sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.14.tgz", + "integrity": "sha512-iG4MlWCcz1L7Yu8AwgsnfVAmMbvyRSk700Mfy2g4c8y5O+Cv1ejshE1LBBsCwHgkuqU0H4R0qu4g23+6UnUemQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^2.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/instrumenter/node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@storybook/instrumenter/node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/manager-api": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-8.6.14.tgz", + "integrity": "sha512-ez0Zihuy17udLbfHZQXkGqwtep0mSGgHcNzGN7iZrMP1m+VmNo+7aGCJJdvXi7+iU3yq8weXSQFWg5DqWgLS7g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/preview-api": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.6.14.tgz", + "integrity": "sha512-2GhcCd4dNMrnD7eooEfvbfL4I83qAqEyO0CO7JQAmIO6Rxb9BsOLLI/GD5HkvQB73ArTJ+PT50rfaO820IExOQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, + "node_modules/@storybook/react": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.6.14.tgz", + "integrity": "sha512-BOepx5bBFwl/CPI+F+LnmMmsG1wQYmrX/UQXgUbHQUU9Tj7E2ndTnNbpIuSLc8IrM03ru+DfwSg1Co3cxWtT+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/components": "8.6.14", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "8.6.14", + "@storybook/preview-api": "8.6.14", + "@storybook/react-dom-shim": "8.6.14", + "@storybook/theming": "8.6.14" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/test": "8.6.14", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.6.14.tgz", + "integrity": "sha512-0hixr3dOy3f3M+HBofp3jtMQMS+sqzjKNgl7Arfuj3fvjmyXOks/yGjDImySR4imPtEllvPZfhiQNlejheaInw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/react-vite": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-8.6.14.tgz", + "integrity": "sha512-FZU0xMPxa4/TO87FgcWwappOxLBHZV5HSRK5K+2bJD7rFJAoNorbHvB4Q1zvIAk7eCMjkr2GPCPHx9PRB9vJFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@joshwooding/vite-plugin-react-docgen-typescript": "0.5.0", + "@rollup/pluginutils": "^5.0.2", + "@storybook/builder-vite": "8.6.14", + "@storybook/react": "8.6.14", + "find-up": "^5.0.0", + "magic-string": "^0.30.0", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@storybook/test": "8.6.14", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.6.14", + "vite": "^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "@storybook/test": { + "optional": true + } + } + }, + "node_modules/@storybook/react-vite/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@storybook/react-vite/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/react-vite/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/test": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.14.tgz", + "integrity": "sha512-GkPNBbbZmz+XRdrhMtkxPotCLOQ1BaGNp/gFZYdGDk2KmUWBKmvc5JxxOhtoXM2703IzNFlQHSSNnhrDZYuLlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.6.14", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.5.0", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "2.0.5", + "@vitest/spy": "2.0.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.6.14" + } + }, + "node_modules/@storybook/test/node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@storybook/test/node_modules/@testing-library/jest-dom": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", + "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/test/node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@storybook/test/node_modules/@vitest/expect": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz", + "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.0.5", + "@vitest/utils": "2.0.5", + "chai": "^5.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@storybook/test/node_modules/@vitest/pretty-format": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz", + "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@storybook/test/node_modules/@vitest/spy": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz", + "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@storybook/test/node_modules/@vitest/utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz", + "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.0.5", + "estree-walker": "^3.0.3", + "loupe": "^3.1.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@storybook/test/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/test/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@storybook/test/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/test/node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "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_modules/@storybook/test/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, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/@storybook/test/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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/test/node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/test/node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/@storybook/test/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/test/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, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@storybook/theming": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-8.6.14.tgz", + "integrity": "sha512-r4y+LsiB37V5hzpQo+BM10PaCsp7YlZ0YcZzQP1OCkPlYXmUAFy2VvDKaFRpD8IeNPKug2u4iFm/laDEbs03dg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" + } + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -6042,6 +7038,301 @@ "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" } }, + "node_modules/@tailwindcss/node": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", + "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.17" + } + }, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", + "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-arm64": "4.1.17", + "@tailwindcss/oxide-darwin-x64": "4.1.17", + "@tailwindcss/oxide-freebsd-x64": "4.1.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", + "@tailwindcss/oxide-linux-x64-musl": "4.1.17", + "@tailwindcss/oxide-wasm32-wasi": "4.1.17", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", + "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", + "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", + "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", + "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", + "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", + "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", + "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", + "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", + "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", + "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.6.0", + "@emnapi/runtime": "^1.6.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.7", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", + "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", + "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz", + "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.17", + "@tailwindcss/oxide": "4.1.17", + "postcss": "^8.4.41", + "tailwindcss": "4.1.17" + } + }, + "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@tailwindcss/typography": { "version": "0.5.9", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.9.tgz", @@ -6412,6 +7703,13 @@ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", @@ -6569,6 +7867,13 @@ "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==", "license": "MIT" }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -6827,6 +8132,13 @@ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -7164,6 +8476,19 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@vitest/runner": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", @@ -8208,7 +9533,7 @@ } }, "node_modules/avanza-ui": { - "resolved": "packages/ui-components", + "resolved": "packages/avanza-ui", "link": true }, "node_modules/axe-core": { @@ -8565,6 +9890,37 @@ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/better-opn/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bfj": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz", @@ -8716,6 +10072,12 @@ "resolved": "packages/broadcast-panel", "link": true }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, "node_modules/browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -10948,6 +12310,16 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -10963,8 +12335,6 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -11753,6 +13123,19 @@ "@esbuild/win32-x64": "0.18.20" } }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -12847,6 +14230,30 @@ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -13367,6 +14774,19 @@ "node": ">= 6" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/formik": { "version": "2.4.9", "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.9.tgz", @@ -16824,6 +18244,16 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz", + "integrity": "sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -17259,8 +18689,6 @@ "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", "dev": true, "license": "MPL-2.0", - "optional": true, - "peer": true, "dependencies": { "detect-libc": "^2.0.3" }, @@ -17935,6 +19363,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true, + "license": "MIT" + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -17986,6 +19421,16 @@ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", "license": "MIT" }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -18483,6 +19928,27 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -19566,33 +21032,35 @@ } }, "node_modules/playwright": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.0.tgz", - "integrity": "sha512-fJGw+HO0YY+fU/F1N57DMO+TmXHTrmr905J05zwAQE9xkuwP/QLDk63rVhmyxh03dYnEhnRbsdbH9B0UVVRB3A==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.0.tgz", + "integrity": "sha512-442pTfGM0xxfCYxuBa/Pu6B2OqxqqaYq39JS8QDMGThUvIOCd6s0ANDog3uwA0cHavVlnTQzGCN7Id2YekDSXA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.38.0" + "playwright-core": "1.51.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.0.tgz", - "integrity": "sha512-f8z1y8J9zvmHoEhKgspmCvOExF2XdcxMW8jNRuX4vkQFrzV4MlZ55iwb5QeyiFQgOFCUolXiRHgpjSEnqvO48g==", + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.0.tgz", + "integrity": "sha512-x47yPE3Zwhlil7wlNU/iktF7t2r/URR3VLbH6EknJd/04Qc/PSJ0EY3CMXipmglLG+zyRxW6HNo2EGbKLHPWMg==", "dev": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/playwright/node_modules/fsevents": { @@ -19609,6 +21077,19 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -21132,6 +22613,16 @@ "fsevents": "2.3.3" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -22416,6 +23907,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/react-docgen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.1.1.tgz", + "integrity": "sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", + "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -22930,6 +24466,46 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/recharts": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", @@ -24802,6 +26378,33 @@ "node": ">= 0.4" } }, + "node_modules/storybook": { + "version": "8.6.14", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.6.14.tgz", + "integrity": "sha512-sVKbCj/OTx67jhmauhxc2dcr1P+yOgz/x3h0krwjyMgdc5Oubvxyg4NYDZmzAw+ym36g/lzH8N0Ccp4dwtdfxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/core": "8.6.14" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, "node_modules/streamx": { "version": "2.23.0", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", @@ -26133,6 +27736,16 @@ "node": ">=14.0.0" } }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tinyspy": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", @@ -26254,6 +27867,16 @@ "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-4.0.0.tgz", "integrity": "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==" }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -27072,6 +28695,20 @@ "node": ">= 0.8" } }, + "node_modules/unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/unquote": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", @@ -27251,6 +28888,20 @@ "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -29257,6 +30908,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/web-vitals": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", @@ -29530,6 +31191,13 @@ "node": ">=10.13.0" } }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -30589,6 +32257,380 @@ "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", "dev": true }, + "packages/avanza-ui": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "rollup": "^4.18.0", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-postcss": "^4.0.2", + "tslib": "^2.6.3", + "typescript": "^5.5.3", + "vitest": "^1.6.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "packages/avanza-ui/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", + "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz", + "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz", + "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz", + "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz", + "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz", + "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz", + "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz", + "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz", + "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz", + "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz", + "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz", + "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz", + "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz", + "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz", + "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz", + "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz", + "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz", + "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz", + "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz", + "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz", + "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "packages/avanza-ui/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz", + "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "packages/avanza-ui/node_modules/rollup": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", + "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.2", + "@rollup/rollup-android-arm64": "4.53.2", + "@rollup/rollup-darwin-arm64": "4.53.2", + "@rollup/rollup-darwin-x64": "4.53.2", + "@rollup/rollup-freebsd-arm64": "4.53.2", + "@rollup/rollup-freebsd-x64": "4.53.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", + "@rollup/rollup-linux-arm-musleabihf": "4.53.2", + "@rollup/rollup-linux-arm64-gnu": "4.53.2", + "@rollup/rollup-linux-arm64-musl": "4.53.2", + "@rollup/rollup-linux-loong64-gnu": "4.53.2", + "@rollup/rollup-linux-ppc64-gnu": "4.53.2", + "@rollup/rollup-linux-riscv64-gnu": "4.53.2", + "@rollup/rollup-linux-riscv64-musl": "4.53.2", + "@rollup/rollup-linux-s390x-gnu": "4.53.2", + "@rollup/rollup-linux-x64-gnu": "4.53.2", + "@rollup/rollup-linux-x64-musl": "4.53.2", + "@rollup/rollup-openharmony-arm64": "4.53.2", + "@rollup/rollup-win32-arm64-msvc": "4.53.2", + "@rollup/rollup-win32-ia32-msvc": "4.53.2", + "@rollup/rollup-win32-x64-gnu": "4.53.2", + "@rollup/rollup-win32-x64-msvc": "4.53.2", + "fsevents": "~2.3.2" + } + }, "packages/backend-api": { "name": "@avanzacast/backend-api", "version": "1.0.0", @@ -32119,49 +34161,445 @@ "packages/studio-panel": { "name": "@avanzacast/studio-panel", "version": "0.2.0", + "license": "ISC", "dependencies": { - "avanza-ui": "file:../ui-components", + "@livekit/components-react": "^2.7.2", + "@livekit/components-styles": "^1.1.5", + "avanza-ui": "file:../avanza-ui", + "livekit-client": "^2.8.2", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { + "@playwright/test": "1.51.0", + "@storybook/addon-essentials": "^8.0.0", + "@storybook/addon-interactions": "^8.0.0", + "@storybook/addon-links": "^8.0.0", + "@storybook/blocks": "^8.0.0", + "@storybook/react": "^8.0.0", + "@storybook/react-vite": "^8.0.0", + "@tailwindcss/postcss": "^4.1.17", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@vitejs/plugin-react": "^4.0.0", + "node-fetch": "^3.3.1", + "playwright": "^1.51.0", + "storybook": "^8.0.0", + "tailwindcss": "^4.1.17", "typescript": "^5.5.0", - "vite": "^4.1.0", + "vite": "^5.0.0", "vitest": "^1.1.8" } }, - "packages/ui-components": { - "name": "avanza-ui", - "version": "1.0.0", + "packages/studio-panel/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "clsx": "^2.1.1" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^25.0.7", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-typescript": "^11.1.6", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "rollup": "^4.18.0", - "rollup-plugin-peer-deps-external": "^2.2.4", - "rollup-plugin-postcss": "^4.0.2", - "tslib": "^2.6.3", - "typescript": "^5.5.3", - "vitest": "^1.6.0" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" } }, - "packages/ui-components/node_modules/@rollup/rollup-android-arm-eabi": { + "packages/studio-panel/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "packages/studio-panel/node_modules/@playwright/test": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.0.tgz", + "integrity": "sha512-dJ0dMbZeHhI+wb77+ljx/FeC8VBP6j/rj9OAojO08JI80wTZy6vRk9KvHKiDCUh4iMpEiseMgqRBIeW+eKX6RA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.51.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "packages/studio-panel/node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==", @@ -32175,7 +34613,7 @@ "android" ] }, - "packages/ui-components/node_modules/@rollup/rollup-android-arm64": { + "packages/studio-panel/node_modules/@rollup/rollup-android-arm64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz", "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==", @@ -32189,7 +34627,7 @@ "android" ] }, - "packages/ui-components/node_modules/@rollup/rollup-darwin-arm64": { + "packages/studio-panel/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz", "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==", @@ -32203,7 +34641,7 @@ "darwin" ] }, - "packages/ui-components/node_modules/@rollup/rollup-darwin-x64": { + "packages/studio-panel/node_modules/@rollup/rollup-darwin-x64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz", "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==", @@ -32217,7 +34655,7 @@ "darwin" ] }, - "packages/ui-components/node_modules/@rollup/rollup-freebsd-arm64": { + "packages/studio-panel/node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz", "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==", @@ -32231,7 +34669,7 @@ "freebsd" ] }, - "packages/ui-components/node_modules/@rollup/rollup-freebsd-x64": { + "packages/studio-panel/node_modules/@rollup/rollup-freebsd-x64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz", "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==", @@ -32245,7 +34683,7 @@ "freebsd" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz", "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==", @@ -32259,7 +34697,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz", "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==", @@ -32273,7 +34711,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-arm64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz", "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==", @@ -32287,7 +34725,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-arm64-musl": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz", "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==", @@ -32301,7 +34739,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-loong64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz", "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==", @@ -32315,7 +34753,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-ppc64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz", "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==", @@ -32329,7 +34767,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz", "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==", @@ -32343,7 +34781,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-riscv64-musl": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz", "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==", @@ -32357,7 +34795,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-s390x-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz", "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==", @@ -32371,7 +34809,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-x64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz", "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==", @@ -32385,7 +34823,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-linux-x64-musl": { + "packages/studio-panel/node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz", "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==", @@ -32399,7 +34837,7 @@ "linux" ] }, - "packages/ui-components/node_modules/@rollup/rollup-openharmony-arm64": { + "packages/studio-panel/node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz", "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==", @@ -32413,7 +34851,7 @@ "openharmony" ] }, - "packages/ui-components/node_modules/@rollup/rollup-win32-arm64-msvc": { + "packages/studio-panel/node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz", "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==", @@ -32427,7 +34865,7 @@ "win32" ] }, - "packages/ui-components/node_modules/@rollup/rollup-win32-ia32-msvc": { + "packages/studio-panel/node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz", "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==", @@ -32441,7 +34879,7 @@ "win32" ] }, - "packages/ui-components/node_modules/@rollup/rollup-win32-x64-gnu": { + "packages/studio-panel/node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz", "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==", @@ -32455,7 +34893,7 @@ "win32" ] }, - "packages/ui-components/node_modules/@rollup/rollup-win32-x64-msvc": { + "packages/studio-panel/node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz", "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==", @@ -32469,7 +34907,75 @@ "win32" ] }, - "packages/ui-components/node_modules/rollup": { + "packages/studio-panel/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "packages/studio-panel/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "packages/studio-panel/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "packages/studio-panel/node_modules/rollup": { "version": "4.53.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", @@ -32511,6 +35017,101 @@ "fsevents": "~2.3.2" } }, + "packages/studio-panel/node_modules/tailwindcss": { + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", + "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "dev": true, + "license": "MIT" + }, + "packages/studio-panel/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "packages/ui-components": { + "name": "avanza-ui", + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "rollup": "^4.18.0", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-postcss": "^4.0.2", + "tslib": "^2.6.3", + "typescript": "^5.5.3", + "vitest": "^1.6.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "packages/vristo-react-main": { "name": "vristo-react-vite", "version": "0.0.0", diff --git a/package.json b/package.json index 138767b..6cb3bb3 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "concurrently": "^8.2.2", - "playwright": "^1.38.0", + "playwright": "^1.51.0", "typescript": "^5.2.2" }, "engines": { diff --git a/packages/avanza-ui/README.md b/packages/avanza-ui/README.md index 1a673d0..dae1d55 100644 --- a/packages/avanza-ui/README.md +++ b/packages/avanza-ui/README.md @@ -1,227 +1,19 @@ -# Avanza-UI +# avanza-ui -Biblioteca de componentes React personalizados para AvanzaCast, basada en el diseño de StreamYard con estilos propios sin dependencias de frameworks CSS. +Librería de componentes reutilizables para AvanzaCast. -## Características +Componentes añadidos en esta entrega: -- ✅ **Sin dependencias de CSS frameworks** - Estilos propios y personalizados -- ✅ **Basado en StreamYard** - Diseño moderno y profesional -- ✅ **TypeScript** - Tipado completo -- ✅ **Tema oscuro** - Optimizado para reducir fatiga visual -- ✅ **Accesible** - Componentes accesibles por defecto -- ✅ **Reutilizable** - Se puede importar desde cualquier package +- `ControlButton` - botón redondo con icono y etiqueta opcional (tamaños: sm|md|lg) +- `IconButton` - botón icon-only para acciones rápidas +- `ControlGroup` - contenedor para agrupar controles +- `ControlBar` - barra de controles centrada que usa `ControlGroup` -## Instalación +Importar desde otros paquetes: -Como esta es una librería local dentro del monorepo, simplemente impórtala en tu package: - -```json -{ - "dependencies": { - "avanza-ui": "workspace:*" - } -} +```ts +import { ControlButton, IconButton, ControlGroup, ControlBar } from 'avanza-ui' ``` -## Uso Básico - -```tsx -import { Button } from 'avanza-ui'; - -function App() { - return ( -

- -
- ); -} -``` - -**Importante:** Asegúrate de envolver tu aplicación con la clase `studio-theme` para aplicar los estilos correctamente. - -## Componentes Disponibles - -### Button - -Botón personalizable con múltiples variantes y tamaños. - -```tsx -import { Button } from 'avanza-ui'; - -// Variantes - - - - - - -// Tamaños - - - - -// Con íconos - - - - -// Estados - - - -// Full width - -``` - -#### Props del Button - -| Prop | Tipo | Default | Descripción | -|------|------|---------|-------------| -| `variant` | `'primary' \| 'secondary' \| 'danger' \| 'success' \| 'ghost'` | `'secondary'` | Variante visual del botón | -| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Tamaño del botón | -| `loading` | `boolean` | `false` | Muestra spinner de carga | -| `disabled` | `boolean` | `false` | Deshabilita el botón | -| `fullWidth` | `boolean` | `false` | Ancho completo | -| `iconOnly` | `boolean` | `false` | Solo muestra ícono (sin texto) | -| `leftIcon` | `ReactNode` | - | Ícono a la izquierda | -| `rightIcon` | `ReactNode` | - | Ícono a la derecha | - -## Variables CSS (Studio Theme) - -Todas las variables CSS están definidas en `studio-theme.css` y pueden ser personalizadas: - -### Colores - -```css ---studio-bg-primary: #0f0f0f; ---studio-bg-secondary: #1a1a1a; ---studio-bg-tertiary: #242424; ---studio-accent: #3b82f6; ---studio-success: #10b981; ---studio-warning: #f59e0b; ---studio-danger: #ef4444; -``` - -### Espaciado - -```css ---studio-space-xs: 4px; ---studio-space-sm: 8px; ---studio-space-md: 12px; ---studio-space-lg: 16px; ---studio-space-xl: 24px; -``` - -### Tipografía - -```css ---studio-text-xs: 11px; ---studio-text-sm: 12px; ---studio-text-base: 14px; ---studio-text-md: 16px; ---studio-text-lg: 18px; -``` - -### Border Radius - -```css ---studio-radius-sm: 4px; ---studio-radius-md: 6px; ---studio-radius-lg: 8px; ---studio-radius-xl: 12px; -``` - -## Personalización - -Puedes sobrescribir las variables CSS en tu aplicación: - -```css -:root { - --studio-accent: #your-color; - --studio-bg-primary: #your-bg; -} -``` - -## Próximos Componentes - -- [ ] Input -- [ ] Select -- [ ] Textarea -- [ ] Checkbox -- [ ] Radio -- [ ] Switch -- [ ] Modal -- [ ] Dropdown -- [ ] Tooltip -- [ ] Card -- [ ] Badge -- [ ] Avatar -- [ ] IconButton -- [ ] Tabs -- [ ] Panel -- [ ] Layout components (StudioLayout, TopBar, BottomBar, etc.) - -## Desarrollo - -### Estructura del Proyecto - -``` -avanza-ui/ -├── src/ -│ ├── components/ -│ │ ├── Button/ -│ │ │ ├── Button.tsx -│ │ │ ├── Button.css -│ │ │ └── index.ts -│ │ └── ... (más componentes) -│ ├── styles/ -│ │ └── studio-theme.css -│ └── index.ts -├── package.json -└── README.md -``` - -### Agregar un Nuevo Componente - -1. Crea una carpeta en `src/components/` -2. Crea `ComponentName.tsx` con el componente React -3. Crea `ComponentName.css` con los estilos -4. Crea `index.ts` para exportar el componente -5. Actualiza `src/index.ts` para exportar desde la raíz - -### Convenciones de Nomenclatura - -- **Componentes**: PascalCase (ej: `Button`, `IconButton`) -- **Archivos**: PascalCase para componentes, kebab-case para estilos -- **CSS Classes**: kebab-case con prefijo `avanza-` (ej: `avanza-button`) -- **CSS Variables**: kebab-case con prefijo `--studio-` (ej: `--studio-accent`) - -## Guía de Estilo - -### CSS - -- Usa variables CSS de `studio-theme.css` en lugar de valores hardcoded -- Sigue el patrón BEM para nombres de clases -- Agrupa propiedades relacionadas -- Usa transiciones para interacciones suaves - -### TypeScript - -- Exporta interfaces de props -- Usa `React.forwardRef` para componentes que necesiten refs -- Documenta props con JSDoc -- Usa tipos estrictos (evita `any`) - -## Licencia - -Uso interno - AvanzaCast - -## Contribuidores - -- Equipo AvanzaCast - ---- - -**Versión:** 1.0.0 -**Última actualización:** 2025-11-11 +Los estilos se importan como efecto secundario al importar `avanza-ui` (archivo `controls.css`). diff --git a/packages/avanza-ui/src/components/ControlBar.tsx b/packages/avanza-ui/src/components/ControlBar.tsx new file mode 100644 index 0000000..dde6e8c --- /dev/null +++ b/packages/avanza-ui/src/components/ControlBar.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { ControlGroup } from './ControlGroup'; + +export interface ControlBarProps { + children?: React.ReactNode; + className?: string; +} + +export const ControlBar: React.FC = ({ children, className }) => { + return ( +
+ + {children} + +
+ ); +}; + +ControlBar.displayName = 'ControlBar'; + +export default ControlBar; diff --git a/packages/avanza-ui/src/components/ControlGroup.module.css b/packages/avanza-ui/src/components/ControlGroup.module.css new file mode 100644 index 0000000..d518298 --- /dev/null +++ b/packages/avanza-ui/src/components/ControlGroup.module.css @@ -0,0 +1,16 @@ +.controlGroup{ + display:flex; + align-items:center; + gap:12px; + padding:6px; + background: transparent; +} + +.controlGroup.center{ + justify-content:center; +} + +.controlGroup.right{ + justify-content:flex-end; +} + diff --git a/packages/avanza-ui/src/components/ControlGroup.tsx b/packages/avanza-ui/src/components/ControlGroup.tsx new file mode 100644 index 0000000..112aa94 --- /dev/null +++ b/packages/avanza-ui/src/components/ControlGroup.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import styles from './ControlGroup.module.css'; + +export interface ControlGroupProps { + children?: React.ReactNode; + className?: string; + style?: React.CSSProperties; +} + +export const ControlGroup: React.FC = ({ children, className, style }) => { + return ( +
+ {children} +
+ ); +}; + +ControlGroup.displayName = 'ControlGroup'; + +export default ControlGroup; + diff --git a/packages/avanza-ui/src/components/IconButton.module.css b/packages/avanza-ui/src/components/IconButton.module.css new file mode 100644 index 0000000..0fed185 --- /dev/null +++ b/packages/avanza-ui/src/components/IconButton.module.css @@ -0,0 +1,21 @@ +.iconButton{ + display:inline-flex; + align-items:center; + justify-content:center; + border-radius:9999px; + background:transparent; + border:1px solid rgba(255,255,255,0.06); + color:var(--au-text-primary, #fff); + cursor:pointer; + transition: transform 120ms ease, background 120ms ease; +} + +.iconButton.sm{width:40px;height:40px;font-size:18px} +.iconButton.md{width:56px;height:56px;font-size:22px} +.iconButton.lg{width:72px;height:72px;font-size:28px} + +.iconButton:hover:not(:disabled){transform:translateY(-3px);background:rgba(255,255,255,0.06)} +.iconButton:active:not(:disabled){transform:translateY(0)} +.iconButton:disabled{opacity:0.5;cursor:not-allowed} +.iconButton.active{box-shadow:0 6px 20px rgba(79,70,229,0.32);background:var(--au-primary)} + diff --git a/packages/avanza-ui/src/components/IconButton.tsx b/packages/avanza-ui/src/components/IconButton.tsx new file mode 100644 index 0000000..0141624 --- /dev/null +++ b/packages/avanza-ui/src/components/IconButton.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import styles from './IconButton.module.css'; +import { cn } from '../utils/helpers'; + +export interface IconButtonProps { + icon?: React.ReactNode; + onClick?: (e?: React.MouseEvent) => void; + active?: boolean; + disabled?: boolean; + title?: string; + size?: 'sm' | 'md' | 'lg'; + id?: string; + className?: string; + style?: React.CSSProperties; +} + +export const IconButton: React.FC = ({ icon, onClick, active = false, disabled = false, title, size = 'md', id, className, style }) => { + return ( + + ); +}; + +IconButton.displayName = 'IconButton'; + +export default IconButton; + diff --git a/packages/avanza-ui/src/components/StudioHeader.module.css b/packages/avanza-ui/src/components/StudioHeader.module.css index 747dea2..70f84f9 100644 --- a/packages/avanza-ui/src/components/StudioHeader.module.css +++ b/packages/avanza-ui/src/components/StudioHeader.module.css @@ -1,12 +1,26 @@ +@import '../styles/globals.css'; + +/* Fallback tokens para análisis estático */ +:root{ + --au-gray-950: #0b1220; + --au-gray-900: #0f172a; + --au-primary: #4f46e5; + --au-primary-hover: #4338ca; + --au-radius-md: 8px; + --au-font-bold: 700; + --au-text-primary: #f1f5f9; + --au-text-secondary: #cbd5e1; +} + .studioHeader { display: flex; align-items: center; justify-content: space-between; - height: 60px; - padding: 0 20px; - background: linear-gradient(180deg, var(--au-gray-800) 0%, var(--au-gray-900) 100%); - border-bottom: 1px solid var(--au-border-dark); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + height: 64px; + padding: 0 24px; + background: linear-gradient(180deg, var(--au-gray-900, #0f172a) 0%, var(--au-gray-950, #0b1220) 100%); + border-bottom: 1px solid rgba(255,255,255,0.03); + box-shadow: 0 6px 22px rgba(2,6,23,0.45); } .headerLeft { @@ -16,19 +30,19 @@ } .headerLogo { - width: 40px; - height: 40px; - border-radius: var(--au-radius-md); + width: 48px; + height: 48px; + border-radius: calc(var(--au-radius-md, 8px) + 4px); display: flex; align-items: center; justify-content: center; - font-weight: var(--au-font-bold); + font-weight: var(--au-font-bold, 700); font-size: 18px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); } .headerLogoGradient { - background: linear-gradient(135deg, var(--au-primary) 0%, var(--au-primary-hover) 100%); + background: linear-gradient(135deg, var(--au-primary, #4f46e5) 0%, var(--au-primary-hover, #4338ca) 100%); color: white; } @@ -39,14 +53,15 @@ } .headerTitleMain { - font-weight: var(--au-font-bold); + font-weight: var(--au-font-bold, 700); font-size: 16px; - color: var(--au-text-primary); + color: var(--au-text-primary, #f1f5f9); } .headerTitleSub { font-size: 12px; - color: var(--au-text-secondary); + color: var(--au-text-secondary, #cbd5e1); + opacity: 0.9; } .headerRight { @@ -54,4 +69,3 @@ align-items: center; gap: 12px; } - diff --git a/packages/avanza-ui/src/components/VideoTile.module.css b/packages/avanza-ui/src/components/VideoTile.module.css index e185de1..efd81be 100644 --- a/packages/avanza-ui/src/components/VideoTile.module.css +++ b/packages/avanza-ui/src/components/VideoTile.module.css @@ -1,23 +1,44 @@ +@import '../styles/globals.css'; + +/* Fallback tokens para análisis estático */ +:root{ + --au-gray-950: #0b1220; + --au-gray-900: #0f172a; + --au-gray-800: #111827; + --au-gray-700: #1f2937; + --au-gray-600: #374151; + --au-primary: #4f46e5; + --au-primary-hover: #4338ca; + --au-warning-500: #f59e0b; + --au-success-500: #10b981; + --au-radius-lg: 12px; + --au-radius-md: 8px; + --au-radius-sm: 4px; + --au-radius-full: 9999px; + --au-transition-fast: 150ms ease; + --au-font-medium: 500; +} + .videoTile { position: relative; aspect-ratio: 16 / 9; - background: linear-gradient(135deg, var(--au-gray-700) 0%, var(--au-gray-800) 100%); - border-radius: var(--au-radius-lg); + background: linear-gradient(135deg, var(--au-gray-700, #1f2937) 0%, var(--au-gray-800, #111827) 100%); + border-radius: var(--au-radius-lg, 12px); overflow: hidden; border: 2px solid transparent; - transition: all var(--au-transition-fast); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + transition: all var(--au-transition-fast, 150ms ease); + box-shadow: 0 8px 28px rgba(15, 23, 42, 0.18); } .videoTile:hover { - border-color: var(--au-primary); - box-shadow: 0 6px 20px rgba(79, 70, 229, 0.3); + border-color: var(--au-primary, #4f46e5); + box-shadow: 0 10px 36px rgba(79, 70, 229, 0.28); transform: translateY(-2px); } .videoTile.speaking { - border-color: var(--au-warning-500); - box-shadow: 0 6px 20px rgba(234, 179, 8, 0.4); + border-color: var(--au-warning-500, #f59e0b); + box-shadow: 0 10px 36px rgba(234, 179, 8, 0.38); } .videoElement { @@ -26,13 +47,13 @@ width: 100%; height: 100%; object-fit: cover; - background-color: var(--au-gray-800); + background-color: var(--au-gray-800, #111827); } .videoOverlay { position: absolute; inset: 0; - background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 50%); + background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.18) 45%, transparent 60%); pointer-events: none; } @@ -66,28 +87,28 @@ } .videoName { - color: white; + color: var(--au-text-on-video, #fff); font-size: 14px; - font-weight: var(--au-font-medium); + font-weight: var(--au-font-medium, 500); max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + text-shadow: 0 2px 6px rgba(0, 0, 0, 0.6); } .videoStatus { - color: rgba(255, 255, 255, 0.9); + color: rgba(255, 255, 255, 0.95); font-size: 12px; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); } .videoControl { - width: 36px; - height: 36px; - border-radius: var(--au-radius-full); + width: 40px; + height: 40px; + border-radius: var(--au-radius-full, 9999px); background: rgba(0, 0, 0, 0.6); - backdrop-filter: blur(4px); + backdrop-filter: blur(6px); color: white; border: none; cursor: pointer; @@ -95,35 +116,34 @@ align-items: center; justify-content: center; font-size: 18px; - transition: all var(--au-transition-fast); + transition: all var(--au-transition-fast, 150ms ease); } .videoControl:hover { - background: rgba(0, 0, 0, 0.8); - transform: scale(1.1); + background: rgba(0, 0, 0, 0.85); + transform: scale(1.06); } .videoControl.muted { - background: rgba(220, 38, 38, 0.9); + background: rgba(225, 29, 72, 0.95); } .qualityIndicator { display: flex; align-items: flex-end; - gap: 2px; + gap: 4px; padding: 4px 8px; background: rgba(0, 0, 0, 0.6); - border-radius: var(--au-radius-md); - backdrop-filter: blur(4px); + border-radius: var(--au-radius-md, 8px); + backdrop-filter: blur(6px); } .qualityBar { - width: 2px; - background: var(--au-success-500); - border-radius: var(--au-radius-sm); + width: 3px; + background: var(--au-success-500, #10b981); + border-radius: var(--au-radius-sm, 4px); } .qualityBar.inactive { - background: var(--au-gray-600); + background: var(--au-gray-600, #374151); } - diff --git a/packages/avanza-ui/src/index.ts b/packages/avanza-ui/src/index.ts index 66c8338..c5c57a6 100644 --- a/packages/avanza-ui/src/index.ts +++ b/packages/avanza-ui/src/index.ts @@ -1,5 +1,6 @@ // Styles import './styles/globals.css'; +import './styles/controls.css'; // Components export { Button } from './components/Button'; @@ -69,6 +70,15 @@ export type { StudioHeaderProps } from './components/StudioHeader'; export { ControlButton } from './components/ControlButton'; export type { ControlButtonProps } from './components/ControlButton'; +export { ControlGroup } from './components/ControlGroup'; +export type { ControlGroupProps } from './components/ControlGroup'; + +export { ControlBar } from './components/ControlBar'; +export type { ControlBarProps } from './components/ControlBar'; + +export { IconButton } from './components/IconButton'; +export type { IconButtonProps } from './components/IconButton'; + export { SceneCard } from './components/SceneCard'; export type { SceneCardProps } from './components/SceneCard'; @@ -80,4 +90,3 @@ export type { ButtonVariant, ButtonSize, Theme, ComponentBaseProps } from './typ // Utils export { cn, formatDate, generateId, debounce, throttle } from './utils/helpers'; - diff --git a/packages/avanza-ui/src/styles/controls.css b/packages/avanza-ui/src/styles/controls.css new file mode 100644 index 0000000..cb63b61 --- /dev/null +++ b/packages/avanza-ui/src/styles/controls.css @@ -0,0 +1,108 @@ +/* controls.css - estilos reutilizables para controles tipo Streamyard + Ubicación: packages/avanza-ui/src/styles/controls.css +*/ + +/* Container for the control bar */ +.controls-inner { + display: inline-flex; + align-items: center; + gap: 12px; + padding: 10px 14px; + background: rgba(0,0,0,0.65); + border-radius: 10px; + color: #fff; +} + +/* Individual control wrapper */ +.control-wrapper { + position: relative; + display: inline-flex; + flex-direction: column; + align-items: center; +} + +/* Button base */ +.btn-control { + display: inline-flex; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + border-radius: 9999px; + background: rgba(255,255,255,0.06); + border: 1px solid rgba(255,255,255,0.06); + color: white; + cursor: pointer; + transition: transform 120ms ease, background 120ms ease, box-shadow 120ms ease; + padding: 6px; +} + +.btn-control:hover { + transform: translateY(-2px); + background: rgba(255,255,255,0.12); +} + +.btn-control:active { + transform: translateY(0); +} + +/* Danger style (record) */ +.btn-control--danger { + background: linear-gradient(180deg, rgba(239,68,68,0.98), rgba(220,38,38,0.98)); + border: 1px solid rgba(0,0,0,0.2); +} + +.btn-control--danger.recording { + box-shadow: 0 6px 18px rgba(239,68,68,0.28), 0 2px 6px rgba(0,0,0,0.3); +} + +/* Small red dot when recording */ +.record-dot { + display: inline-block; + width: 10px; + height: 10px; + background: var(--studio-recording, #ef4444); + border-radius: 9999px; + margin-right: 8px; + box-shadow: 0 4px 10px rgba(239,68,68,0.28); +} + +/* Tooltip below controls */ +.tooltip { + position: absolute; + bottom: -30px; + left: 50%; + transform: translateX(-50%); + background: rgba(31,41,55,0.92); + color: #fff; + padding: 6px 8px; + border-radius: 6px; + font-size: 12px; + white-space: nowrap; + display: none; + opacity: 0; + transition: opacity 120ms ease, transform 120ms ease; +} + +.control-wrapper:hover .tooltip { + display: block; + opacity: 1; + transform: translateX(-50%) translateY(-4px); +} + +/* Visual hidden utility */ +.visually-hidden { + position: absolute !important; + height: 1px; width: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); + white-space: nowrap; + border: 0; padding: 0; margin: -1px; +} + +/* Responsive placement for small screens */ +@media (max-width: 640px) { + .controls-inner { padding: 8px 10px; gap: 8px; } + .btn-control { width: 40px; height: 40px; } +} + diff --git a/packages/avanza-ui/src/styles/globals.css b/packages/avanza-ui/src/styles/globals.css index e69de29..2716f2b 100644 --- a/packages/avanza-ui/src/styles/globals.css +++ b/packages/avanza-ui/src/styles/globals.css @@ -0,0 +1,154 @@ +/* avanza-ui global tokens and resets */ +:root{ + /* Colors */ + --au-gray-950: #0b1220; + --au-gray-900: #0f172a; + --au-gray-800: #111827; + --au-gray-700: #1f2937; + --au-gray-600: #374151; + --au-gray-600-2: #4b5563; + + --au-primary: #4f46e5; + --au-primary-hover: #4338ca; + --au-success-500: #10b981; + --au-warning-500: #f59e0b; + --au-danger-500: #ef4444; + + --au-text-primary: #f1f5f9; + --au-text-secondary: #cbd5e1; + + /* Radius */ + --au-radius-sm: 4px; + --au-radius-md: 8px; + --au-radius-lg: 12px; + --au-radius-full: 9999px; + + /* Typography */ + --au-font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + --au-font-bold: 700; + --au-font-medium: 500; + --au-font-normal: 400; + + /* Transitions */ + --au-transition-fast: 150ms ease; + --au-transition-medium: 250ms ease; + --au-transition-slow: 400ms ease; + + /* Shadows */ + --au-shadow-sm: 0 4px 12px rgba(2,6,23,0.18); + --au-shadow-md: 0 8px 24px rgba(2,6,23,0.28); +} + +/* Light theme overrides (if used in non-dark mode) */ +[data-theme="light"]{ + --au-text-primary: #1f2937; + --au-text-secondary: #6b7280; + --au-gray-950: #f8fafc; + --au-gray-900: #ffffff; + --au-gray-800: #f3f4f6; + --au-gray-700: #e5e7eb; + --au-gray-600: #9ca3af; +} + +/* Basic resets for avanza-ui components */ +.au-root, .avanza-ui-root { + font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + color: var(--au-text-primary); +} + +button { font-family: inherit } + +/* Ensure modal/backdrop stacking works */ +.avanza-ui-modal-backdrop { z-index: 9999 } + +/* Compatibility tokens for other packages (broadcast-panel / studio-panel) + These map commonly used project tokens to the avanza-ui design tokens so + all packages can import the avanza-ui globals and get consistent values. +*/ +:root{ + /* Broadcast-style tokens */ + --primary-blue: var(--au-primary); + --primary-blue-hover: var(--au-primary-hover); + --background-color: var(--au-gray-950); + --surface-color: var(--au-gray-900); + --text-primary: var(--au-text-primary); + --text-secondary: var(--au-text-secondary); + --border-light: rgba(255,255,255,0.04); + --active-bg-light: rgba(79,70,229,0.06); + --shadow-sm: var(--au-shadow-sm); + --shadow-md: var(--au-shadow-md); + --skeleton-base: #e5e7eb; + --skeleton-highlight: #f3f4f6; + + /* Surface tokens used by studio-panel */ + --surface-50: #f8fafc; + --surface-900: #0f172a; + + /* Studio specific tokens (map to avanza-ui tokens) */ + --studio-bg-primary: var(--background-color); + --studio-bg-secondary: var(--surface-color); + --studio-bg-tertiary: var(--active-bg-light); + --studio-bg-elevated: var(--surface-color); + --studio-bg-hover: rgba(255,255,255,0.02); + + --studio-border: var(--border-light); + --studio-border-light: rgba(255,255,255,0.02); + --studio-border-subtle: rgba(255,255,255,0.01); + + --studio-text-primary: var(--text-primary); + --studio-text-secondary: var(--text-secondary); + --studio-text-muted: #94a3b8; + --studio-text-disabled: #9ca3af; + + --studio-accent: var(--primary-blue); + --studio-accent-hover: var(--primary-blue-hover); + --studio-accent-light: rgba(79,70,229,0.08); + + --studio-success: var(--au-success-500); + --studio-warning: var(--au-warning-500); + --studio-danger: var(--au-danger-500); + + --studio-recording: var(--au-danger-500); + --studio-recording-pulse: rgba(239, 68, 68, 0.12); + + --studio-space-xs: 4px; + --studio-space-sm: 8px; + --studio-space-md: 12px; + --studio-space-lg: 16px; + --studio-space-xl: 24px; + + --studio-radius-sm: var(--au-radius-sm); + --studio-radius-md: var(--au-radius-md); + --studio-radius-lg: var(--au-radius-lg); + --studio-radius-xl: calc(var(--au-radius-lg) + 4px); + + --studio-font-family: var(--au-font-family, 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif); + --studio-text-base: 14px; + --studio-text-sm: 12px; + + /* Additional studio tokens required by studio-theme.css and components */ + --studio-font-normal: var(--au-font-normal, 400); + --studio-leading-normal: 1.4; + --studio-radius-full: var(--au-radius-full, 9999px); + + --studio-shadow-sm: var(--au-shadow-sm); + --studio-shadow-md: var(--au-shadow-md); + --studio-shadow-lg: 0 12px 40px rgba(2,6,23,0.32); + + --studio-transition: 200ms ease; + --studio-transition-fast: 120ms ease; + --studio-transition-slow: 320ms ease; +} + +/* Light theme compatibility mapping */ +[data-theme="light"]{ + --primary-blue: var(--au-primary); + --background-color: #f7f8fa; + --surface-color: #ffffff; + --text-primary: #1f2937; + --text-secondary: #6b7280; + --surface-50: #f8fafc; + --surface-900: #0f172a; +} + +/* End of compatibility tokens */ diff --git a/packages/avanza-ui/src/styles/studio-theme.css b/packages/avanza-ui/src/styles/studio-theme.css index 0febc61..9be6ddc 100644 --- a/packages/avanza-ui/src/styles/studio-theme.css +++ b/packages/avanza-ui/src/styles/studio-theme.css @@ -1,3 +1,5 @@ +@import './globals.css'; + /** * Studio Theme - Basado en el análisis de StreamYard * Versión: 1.0 @@ -5,133 +7,117 @@ */ :root { - /* ===== COLORS ===== */ - /* Backgrounds */ - --studio-bg-primary: #0f0f0f; - --studio-bg-secondary: #1a1a1a; - --studio-bg-tertiary: #242424; - --studio-bg-elevated: #2a2a2a; - --studio-bg-hover: #333333; + /* ===== BROADCAST-PANEL COMPATIBILITY (LIGHT THEME) ===== */ + /* These variables mirror names used in broadcast-panel/src/styles.css to ease reuse */ + --primary-blue: #4f46e5; + --primary-blue-hover: #4338ca; + --background-color: #f7f8fa; + --surface-color: #ffffff; + --text-primary: #1f2937; + --text-secondary: #6b7280; + --border-light: #e5e7eb; + --active-bg-light: #eef2ff; + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + --shadow-md: 0 1px 3px 0 rgba(0, 0, 0, 0.1); + --shadow-lg: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + --skeleton-base: #e5e7eb; + --skeleton-highlight: #f3f4f6; + + /* ===== STUDIO TOKENS (light mode) ===== */ + --studio-bg-primary: var(--background-color); + --studio-bg-secondary: #f2f4f8; /* subtle surface */ + --studio-bg-tertiary: #eef2ff; /* accent panel */ + --studio-bg-elevated: var(--surface-color); + --studio-bg-hover: #f3f5f9; /* Borders */ - --studio-border: #333333; - --studio-border-light: #404040; - --studio-border-subtle: #2a2a2a; + --studio-border: var(--border-light); + --studio-border-light: #f1f5f9; + --studio-border-subtle: #eef2f6; /* Text */ - --studio-text-primary: #ffffff; - --studio-text-secondary: #e0e0e0; - --studio-text-muted: #999999; - --studio-text-disabled: #666666; + --studio-text-primary: var(--text-primary); + --studio-text-secondary: var(--text-secondary); + --studio-text-muted: #64748b; + --studio-text-disabled: #9ca3af; /* Accent Colors */ - --studio-accent: #3b82f6; - --studio-accent-hover: #2563eb; - --studio-accent-light: rgba(59, 130, 246, 0.1); + --studio-accent: var(--primary-blue); + --studio-accent-hover: var(--primary-blue-hover); + --studio-accent-light: rgba(79, 70, 229, 0.08); /* Status Colors */ --studio-success: #10b981; - --studio-success-hover: #059669; --studio-warning: #f59e0b; - --studio-warning-hover: #d97706; --studio-danger: #ef4444; - --studio-danger-hover: #dc2626; - /* Recording State */ + /* Recording */ --studio-recording: #ef4444; - --studio-recording-pulse: rgba(239, 68, 68, 0.4); + --studio-recording-pulse: rgba(239, 68, 68, 0.12); - /* ===== SPACING ===== */ + /* Spacing, radius, typography copied from previous tokens */ --studio-space-xs: 4px; --studio-space-sm: 8px; --studio-space-md: 12px; --studio-space-lg: 16px; --studio-space-xl: 24px; - --studio-space-2xl: 32px; - --studio-space-3xl: 48px; - /* ===== BORDER RADIUS ===== */ --studio-radius-sm: 4px; --studio-radius-md: 6px; --studio-radius-lg: 8px; --studio-radius-xl: 12px; - --studio-radius-2xl: 16px; - --studio-radius-full: 9999px; - /* ===== SHADOWS ===== */ - --studio-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3); - --studio-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); - --studio-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4); - --studio-shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.5); - --studio-shadow-xl: 0 20px 40px rgba(0, 0, 0, 0.6); - - /* ===== TRANSITIONS ===== */ - --studio-transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); - --studio-transition-fast: all 100ms cubic-bezier(0.4, 0, 0.2, 1); - --studio-transition-slow: all 250ms cubic-bezier(0.4, 0, 0.2, 1); - - /* ===== TYPOGRAPHY ===== */ - --studio-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', - 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', - 'Helvetica Neue', sans-serif; - - /* Font Sizes */ - --studio-text-xs: 11px; - --studio-text-sm: 12px; + --studio-font-family: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', system-ui, sans-serif; --studio-text-base: 14px; - --studio-text-md: 16px; - --studio-text-lg: 18px; - --studio-text-xl: 20px; - --studio-text-2xl: 24px; + --studio-text-sm: 12px; +} - /* Font Weights */ - --studio-font-normal: 400; - --studio-font-medium: 500; - --studio-font-semibold: 600; - --studio-font-bold: 700; +/* Dark theme preserves previous studio variables but also map broadcast-panel dark tokens for compatibility */ +[data-theme="dark"] { + /* broadcast-panel dark equivalents */ + --primary-blue: #6366f1; + --primary-blue-hover: #4f46e5; + --background-color: #0f172a; + --surface-color: #1e293b; + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --border-light: #334155; + --active-bg-light: #312e81; + --shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.3); + --shadow-md: 0 1px 3px 0 rgba(0,0,0,0.4); + --shadow-lg: 0 4px 6px -1px rgba(0,0,0,0.5); + --skeleton-base: #334155; + --skeleton-highlight: #475569; - /* Line Heights */ - --studio-leading-tight: 1.2; - --studio-leading-normal: 1.5; - --studio-leading-relaxed: 1.75; + /* studio theme dark overrides */ + --studio-bg-primary: var(--background-color); + --studio-bg-secondary: var(--surface-color); + --studio-bg-tertiary: #111827; /* dark panel */ + --studio-bg-elevated: #0b1220; + --studio-bg-hover: #0f172a; - /* ===== SIZING ===== */ - /* Button Sizes */ - --studio-btn-sm-height: 32px; - --studio-btn-md-height: 40px; - --studio-btn-lg-height: 48px; + --studio-border: var(--border-light); + --studio-border-light: #24303b; + --studio-border-subtle: #1f2a36; - /* Icon Sizes */ - --studio-icon-xs: 14px; - --studio-icon-sm: 16px; - --studio-icon-md: 20px; - --studio-icon-lg: 24px; - --studio-icon-xl: 32px; + --studio-text-primary: var(--text-primary); + --studio-text-secondary: var(--text-secondary); + --studio-text-muted: #94a3b8; + --studio-text-disabled: #6b7280; - /* Panel Widths */ - --studio-panel-left-width: 220px; - --studio-panel-right-width: 320px; - --studio-panel-collapsed-width: 60px; - - /* ===== Z-INDEX ===== */ - --studio-z-base: 1; - --studio-z-dropdown: 1000; - --studio-z-sticky: 1020; - --studio-z-fixed: 1030; - --studio-z-overlay: 1040; - --studio-z-modal: 1050; - --studio-z-popover: 1060; - --studio-z-tooltip: 1070; + --studio-accent: var(--primary-blue); + --studio-accent-hover: var(--primary-blue-hover); + --studio-accent-light: rgba(99, 102, 241, 0.08); } /* ===== GLOBAL RESETS ===== */ .studio-theme { - font-family: var(--studio-font-family); - font-size: var(--studio-text-base); - font-weight: var(--studio-font-normal); - line-height: var(--studio-leading-normal); - color: var(--studio-text-primary); - background-color: var(--studio-bg-primary); + font-family: var(--studio-font-family, var(--au-font-family, 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif)); + font-size: var(--studio-text-base, 14px); + font-weight: var(--studio-font-normal, 400); + line-height: var(--studio-leading-normal, 1.4); + color: var(--studio-text-primary, #111827); + background-color: var(--studio-bg-primary, #f7f8fa); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -151,54 +137,54 @@ } .studio-theme ::-webkit-scrollbar-track { - background: var(--studio-bg-secondary); + background: var(--studio-bg-secondary, #f2f4f8); } .studio-theme ::-webkit-scrollbar-thumb { - background: var(--studio-bg-hover); - border-radius: var(--studio-radius-full); + background: var(--studio-bg-hover, #f3f5f9); + border-radius: var(--studio-radius-full, 9999px); } .studio-theme ::-webkit-scrollbar-thumb:hover { - background: var(--studio-border-light); + background: var(--studio-border-light, rgba(255,255,255,0.02)); } /* ===== UTILITY CLASSES ===== */ /* Backgrounds */ -.bg-primary { background-color: var(--studio-bg-primary); } -.bg-secondary { background-color: var(--studio-bg-secondary); } -.bg-tertiary { background-color: var(--studio-bg-tertiary); } -.bg-elevated { background-color: var(--studio-bg-elevated); } -.bg-hover { background-color: var(--studio-bg-hover); } +.bg-primary { background-color: var(--studio-bg-primary, #f7f8fa); } +.bg-secondary { background-color: var(--studio-bg-secondary, #f2f4f8); } +.bg-tertiary { background-color: var(--studio-bg-tertiary, #eef2ff); } +.bg-elevated { background-color: var(--studio-bg-elevated, #ffffff); } +.bg-hover { background-color: var(--studio-bg-hover, #f3f5f9); } /* Text Colors */ -.text-primary { color: var(--studio-text-primary); } -.text-secondary { color: var(--studio-text-secondary); } -.text-muted { color: var(--studio-text-muted); } -.text-disabled { color: var(--studio-text-disabled); } +.text-primary { color: var(--studio-text-primary, #1f2937); } +.text-secondary { color: var(--studio-text-secondary, #6b7280); } +.text-muted { color: var(--studio-text-muted, #64748b); } +.text-disabled { color: var(--studio-text-disabled, #9ca3af); } /* Borders */ -.border { border: 1px solid var(--studio-border); } -.border-light { border: 1px solid var(--studio-border-light); } -.border-subtle { border: 1px solid var(--studio-border-subtle); } +.border { border: 1px solid var(--studio-border, rgba(0,0,0,0.06)); } +.border-light { border: 1px solid var(--studio-border-light, rgba(0,0,0,0.03)); } +.border-subtle { border: 1px solid var(--studio-border-subtle, rgba(0,0,0,0.02)); } /* Radius */ -.rounded-sm { border-radius: var(--studio-radius-sm); } -.rounded-md { border-radius: var(--studio-radius-md); } -.rounded-lg { border-radius: var(--studio-radius-lg); } -.rounded-xl { border-radius: var(--studio-radius-xl); } -.rounded-full { border-radius: var(--studio-radius-full); } +.rounded-sm { border-radius: var(--studio-radius-sm, 4px); } +.rounded-md { border-radius: var(--studio-radius-md, 6px); } +.rounded-lg { border-radius: var(--studio-radius-lg, 8px); } +.rounded-xl { border-radius: var(--studio-radius-xl, 12px); } +.rounded-full { border-radius: var(--studio-radius-full, 9999px); } /* Shadows */ -.shadow-sm { box-shadow: var(--studio-shadow-sm); } -.shadow-md { box-shadow: var(--studio-shadow-md); } -.shadow-lg { box-shadow: var(--studio-shadow-lg); } +.shadow-sm { box-shadow: var(--studio-shadow-sm, 0 1px 2px rgba(0,0,0,0.05)); } +.shadow-md { box-shadow: var(--studio-shadow-md, 0 4px 12px rgba(0,0,0,0.08)); } +.shadow-lg { box-shadow: var(--studio-shadow-lg, 0 12px 40px rgba(2,6,23,0.12)); } /* Transitions */ -.transition { transition: var(--studio-transition); } -.transition-fast { transition: var(--studio-transition-fast); } -.transition-slow { transition: var(--studio-transition-slow); } +.transition { transition: var(--studio-transition, 200ms ease); } +.transition-fast { transition: var(--studio-transition-fast, 120ms ease); } +.transition-slow { transition: var(--studio-transition-slow, 320ms ease); } /* ===== ANIMATIONS ===== */ @keyframes pulse-recording { @@ -256,4 +242,3 @@ .animate-slide-in-left { animation: slide-in-left 250ms ease-out; } - diff --git a/packages/backend-api/.env.production b/packages/backend-api/.env.production new file mode 100644 index 0000000..f56993e --- /dev/null +++ b/packages/backend-api/.env.production @@ -0,0 +1,15 @@ +# Backend API production env (DO NOT commit secrets in public repos) +VITE_STUDIO_URL=https://avanzacast-studio.bfzqqk.easypanel.host +VITE_BROADCASTPANEL_URL=https://avanzacast-broadcastpanel.bfzqqk.easypanel.host +VITE_TOKEN_SERVER_URL=https://avanzacast-servertokens.bfzqqk.easypanel.host + +# LiveKit credentials - set real values in your production environment or CI secrets +LIVEKIT_API_KEY=devkey +LIVEKIT_API_SECRET=secretsecretsecretsecretsecretsecret +LIVEKIT_URL=wss://livekit-server.bfzqqk.easypanel.host + +# Allow frontend origins (production) +FRONTEND_URLS=https://avanzacast-broadcastpanel.bfzqqk.easypanel.host,https://avanzacast-studio.bfzqqk.easypanel.host + +PORT=4000 +NODE_ENV=production diff --git a/packages/backend-api/Dockerfile b/packages/backend-api/Dockerfile new file mode 100644 index 0000000..533dcfd --- /dev/null +++ b/packages/backend-api/Dockerfile @@ -0,0 +1,28 @@ +# Multi-stage Dockerfile for backend-api +# Build stage: install deps and compile +FROM node:20-bullseye-slim AS builder +WORKDIR /app + +# Install build dependencies +COPY package.json package-lock.json* ./ +# Try npm ci (fast & reproducible). If package-lock.json is missing, fallback to npm install +RUN apt-get update && apt-get install -y --no-install-recommends python3 build-essential ca-certificates && rm -rf /var/lib/apt/lists/* \ + && (npm ci --no-audit --no-fund || npm install --no-audit --no-fund) + +# Copy source and build +COPY . . +RUN npm run build + +# Production stage: copy built files and production deps +FROM node:20-bullseye-slim +WORKDIR /app +# Copy node_modules from builder (includes production deps) +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/dist ./dist + +ENV NODE_ENV=production +ENV HOST=0.0.0.0 +ENV PORT=4000 +EXPOSE 4000 + +CMD ["node", "dist/index.js"] diff --git a/packages/backend-api/build_and_run_backend.sh b/packages/backend-api/build_and_run_backend.sh new file mode 100755 index 0000000..e74275a --- /dev/null +++ b/packages/backend-api/build_and_run_backend.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT=$(cd "$(dirname "$0")" && pwd) +cd "$ROOT" + +IMAGE_TAG="avanzacast/backend-api:local" + +# Build the image +docker build -t "$IMAGE_TAG" . + +# Run container mapping port 4000 +CONTAINER_NAME="avz_backend_local" +# stop existing +docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true + +docker run -d --name "$CONTAINER_NAME" -p 4000:4000 \ + -e HOST=0.0.0.0 -e PORT=4000 \ + "$IMAGE_TAG" + +echo "Started container $CONTAINER_NAME (image $IMAGE_TAG)" + +echo 'Wait 2s then curl /health' +sleep 2 +curl -sS http://localhost:4000/health || true + diff --git a/packages/backend-api/package.json b/packages/backend-api/package.json index b32639e..bad9f7f 100644 --- a/packages/backend-api/package.json +++ b/packages/backend-api/package.json @@ -5,7 +5,7 @@ "description": "AvanzaCast - Backend API", "type": "module", "scripts": { - "dev": "tsx watch src/index.ts", + "dev": "npx tsx watch src/index.ts", "build": "tsc", "start": "node dist/index.js", "typecheck": "tsc --noEmit", diff --git a/packages/backend-api/src/index.ts b/packages/backend-api/src/index.ts index a35db1a..ff41bc9 100644 --- a/packages/backend-api/src/index.ts +++ b/packages/backend-api/src/index.ts @@ -2,126 +2,296 @@ import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import dotenv from 'dotenv'; +import os from 'os'; +import Redis from 'ioredis'; dotenv.config(); const app = express(); -const PORT = process.env.PORT || 4000; +const PORT = process.env.PORT ? Number(process.env.PORT) : 4000; + +// Redis setup (optional) +const REDIS_URL = process.env.REDIS_URL || process.env.REDIS || 'redis://localhost:6379'; +let redisClient: Redis | null = null; +let redisAvailable = false; +try { + redisClient = new Redis(REDIS_URL); + redisClient.on('error', (err: any) => console.warn('[Redis] error', err)); + redisClient.on('connect', () => { redisAvailable = true; console.log('[Redis] connected') }); +} catch (e) { + console.warn('Redis init failed, falling back to memory store', e); + redisClient = null; +} // Middleware app.use(helmet()); -const allowedOrigins = process.env.FRONTEND_URLS?.split(',') || ['http://localhost:3000']; -// Always allow our local dev studio ports to avoid CORS blockers during development -if (process.env.NODE_ENV !== 'production') { - if (!allowedOrigins.includes('http://localhost:3020')) allowedOrigins.push('http://localhost:3020') - if (!allowedOrigins.includes('http://localhost:3021')) allowedOrigins.push('http://localhost:3021') - if (!allowedOrigins.includes('http://localhost:5175')) allowedOrigins.push('http://localhost:5175') - if (!allowedOrigins.includes('https://avanzacast-studio.bfzqqk.easypanel.host')) allowedOrigins.push('https://avanzacast-studio.bfzqqk.easypanel.host') - if (!allowedOrigins.includes('https://avanzacast-broadcastpanel.bfzqqk.easypanel.host')) allowedOrigins.push('https://avanzacast-broadcastpanel.bfzqqk.easypanel.host') -} - -app.use(cors({ - origin: allowedOrigins, - credentials: true, -})); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -// Health check -app.get('/health', (req, res) => { - res.json({ status: 'ok', timestamp: new Date().toISOString() }); +// CORS setup +function normalizeOrigin(u?: string) { + if (!u) return undefined; + try { return u.replace(/\/$/, '') } catch { return u } +} + +const allowedSet = new Set(); +const fromEnv = process.env.FRONTEND_URLS ? process.env.FRONTEND_URLS.split(',').map(s => s.trim()).filter(Boolean) : []; +fromEnv.forEach(u => { const n = normalizeOrigin(u); if (n) allowedSet.add(n) }); + +// local dev origins +['http://localhost:3000','http://localhost:3020','http://localhost:3021','http://localhost:5175'].forEach(x => allowedSet.add(x)); +const studioUrl = normalizeOrigin(process.env.VITE_STUDIO_URL); +const broadcastUrl = normalizeOrigin(process.env.VITE_BROADCASTPANEL_URL); +const tokenServerUrl = normalizeOrigin(process.env.VITE_TOKEN_SERVER_URL); +if (studioUrl) allowedSet.add(studioUrl); +if (broadcastUrl) allowedSet.add(broadcastUrl); +if (tokenServerUrl) allowedSet.add(tokenServerUrl); + +// Automatically enable allow-subdomain check when envs point to the easypanel host +let allowSubdomainEnv = process.env.ALLOW_SUBDOMAIN_EASYPANEL === '1'; +try { + const easypanelHosts = ['.bfzqqk.easypanel.host']; + const candidates = [...fromEnv, studioUrl || '', broadcastUrl || '', tokenServerUrl || '']; + const found = candidates.some(c => !!c && easypanelHosts.some(h => c.includes(h))); + if (found) { + allowSubdomainEnv = true; + // Do not overwrite explicit config, but log the auto-detection + console.log('Auto-detected easypanel host in envs — enabling ALLOW_SUBDOMAIN_EASYPANEL behavior'); + } +} catch (e) {} + +if (allowSubdomainEnv) process.env.ALLOW_SUBDOMAIN_EASYPANEL = '1'; + +console.log('CORS allowed origins:', Array.from(allowedSet)); + +function isOriginAllowed(originHeader?: string) { + if (!originHeader) return false; + const origin = originHeader.toString().replace(/\/$/, ''); + if (process.env.ALLOW_ALL_CORS === '1') return true; + if (allowedSet.has(origin)) return true; + if (process.env.ALLOW_SUBDOMAIN_EASYPANEL === '1') { + try { + const host = new URL(origin).hostname; + if (host && host.endsWith('.bfzqqk.easypanel.host')) return true; + } catch (e) { + // ignore + } + } + return false; +} + +// Handle preflight quickly +app.use((req, res, next) => { + try { + if (req.method === 'OPTIONS') { + const origin = (req.headers.origin || '').toString().replace(/\/$/, ''); + if (!origin) return res.status(204).send(); + if (isOriginAllowed(origin)) { + res.setHeader('Access-Control-Allow-Origin', process.env.ALLOW_ALL_CORS === '1' ? '*' : origin); + res.setHeader('Access-Control-Allow-Credentials', 'true'); + res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization'); + return res.status(204).send(); + } + return res.status(403).send('CORS origin not allowed'); + } + } catch (e) { console.warn('preflight error', e) } + next(); }); -// API Routes -app.get('/api/v1', (req, res) => { - res.json({ - message: 'AvanzaCast Backend API', - version: '1.0.0', - endpoints: { - auth: '/api/v1/auth', - users: '/api/v1/users', - broadcasts: '/api/v1/broadcasts', - subscriptions: '/api/v1/subscriptions', - integrations: '/api/v1/integrations', +if (process.env.ALLOW_ALL_CORS === '1') { + console.warn('⚠️ ALLOW_ALL_CORS=1 is set — allowing all origins for debugging'); + app.use(cors({ origin: true, credentials: true })); +} else { + app.use(cors({ + origin: function(origin, callback) { + if (!origin) return callback(null, true); + if (isOriginAllowed(origin)) return callback(null, true); + console.warn('[CORS] blocked origin:', origin); + return callback(new Error('Not allowed by CORS'), false); }, - }); + credentials: true, + })); +} + +app.use((req, res, next) => { + try { + const origin = (req.headers.origin || '').toString(); + if (origin && isOriginAllowed(origin)) { + res.setHeader('Access-Control-Allow-Origin', process.env.ALLOW_ALL_CORS === '1' ? '*' : origin); + res.setHeader('Access-Control-Allow-Credentials', 'true'); + } + } catch (e) {} + next(); }); -// LiveKit token generation endpoint -app.get('/api/token', async (req, res) => { - const { room, username } = req.query; - - if (!room || typeof room !== 'string') { - return res.status(400).json({ error: 'Room name is required' }); - } - - if (!username || typeof username !== 'string') { - return res.status(400).json({ error: 'Username is required' }); - } +// Logging middleware +app.use((req, res, next) => { + try { + const bodyPreview = req.body && Object.keys(req.body).length ? JSON.stringify(req.body).slice(0, 500) : ''; + console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} from ${req.ip} ${bodyPreview}`); + } catch (e) { console.warn('logging error', e) } + next(); +}); - // TODO: Implement actual LiveKit token generation - // For now, return a placeholder response +app.get('/health', (_req, res) => res.json({ status: 'ok', timestamp: new Date().toISOString() })); + +function generateShortId(len = 7) { + const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; + let s = ''; + for (let i = 0; i < len; i++) s += chars[Math.floor(Math.random() * chars.length)]; + return s; +} + +const SESSION_TTL = Number(process.env.SESSION_TTL_SECONDS || 300); +const sessionStoreMemory = new Map(); + +async function saveSession(id: string, data: { token: string, url: string, room: string, username: string }, ttlSeconds: number) { + const payload = { ...data, expiresAt: Date.now() + ttlSeconds * 1000 }; + if (redisClient && redisAvailable) { + await redisClient.setex(`session:${id}`, ttlSeconds, JSON.stringify(payload)); + } else { + sessionStoreMemory.set(id, { ...payload }); + setTimeout(() => { sessionStoreMemory.delete(id) }, ttlSeconds * 1000 + 1000); + } +} + +async function getSession(id: string): Promise { + if (redisClient && redisAvailable) { + const raw = await redisClient.get(`session:${id}`); + if (!raw) return null; + try { return JSON.parse(raw) } catch (e) { return null } + } + const s = sessionStoreMemory.get(id); + if (!s) return null; + if (s.expiresAt <= Date.now()) { sessionStoreMemory.delete(id); return null } + return s; +} + +async function createLivekitTokenFor(room: string, username: string) { const LIVEKIT_API_KEY = process.env.LIVEKIT_API_KEY; const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET; - if (!LIVEKIT_API_KEY || !LIVEKIT_API_SECRET) { - console.error('⚠️ LIVEKIT_API_KEY and LIVEKIT_API_SECRET must be set in environment variables'); - return res.status(500).json({ error: 'LiveKit credentials not configured' }); + const fakeToken = `devtoken-${Math.random().toString(36).slice(2,10)}`; + return { token: fakeToken, url: process.env.LIVEKIT_URL || 'ws://localhost:7880' }; } + const { AccessToken } = await import('livekit-server-sdk'); + const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, { identity: username, name: username }); + at.addGrant({ room, roomJoin: true, canPublish: true, canSubscribe: true }); + const token = await at.toJwt(); + return { token, url: process.env.LIVEKIT_URL || 'ws://localhost:7880' }; +} +app.get('/api/token', async (req, res) => { + const { room, username } = req.query as Record; + if (!room || typeof room !== 'string') return res.status(400).json({ error: 'Room name is required' }); + if (!username || typeof username !== 'string') return res.status(400).json({ error: 'Username is required' }); try { - // Import AccessToken from livekit-server-sdk - const { AccessToken } = await import('livekit-server-sdk'); - - const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, { - identity: username, - name: username, - }); - - at.addGrant({ - room, - roomJoin: true, - canPublish: true, - canSubscribe: true, - }); - - const token = await at.toJwt(); - - return res.json({ - token, - url: process.env.LIVEKIT_URL || 'ws://localhost:7880', - }); - } catch (error) { - console.error('Error generating LiveKit token:', error); + const { token, url } = await createLivekitTokenFor(room, username); + return res.json({ token, url }); + } catch (err) { + console.error('Error generating token', err); return res.status(500).json({ error: 'Failed to generate token' }); } }); -// Minimal LiveKit-related endpoints (placeholder implementation) -app.get('/api/v1/livekit/rooms', (req, res) => { - const roomName = typeof req.query.roomName === 'string' ? req.query.roomName : undefined; +app.post('/api/session', async (req, res) => { + try { + const body = req.body || {}; + const room = typeof body.room === 'string' ? body.room : undefined; + const username = typeof body.username === 'string' ? body.username : undefined; + const ttl = body.ttl ? Number(body.ttl) : undefined; + if (!room) return res.status(400).json({ error: 'room is required' }); + if (!username) return res.status(400).json({ error: 'username is required' }); - // If no roomName provided, return a list of rooms (empty list for now) - if (!roomName) { - return res.json({ rooms: [] }); + const { token, url } = await createLivekitTokenFor(room, username); + + let id = generateShortId(7); + let attempt = 0; + while (attempt < 6) { + const exists = await getSession(id); + if (!exists) break; + id = generateShortId(7); + attempt++; + } + const ttlSec = ttl || SESSION_TTL; + await saveSession(id, { token, url, room, username }, ttlSec); + + const studioBase = (process.env.VITE_STUDIO_URL || 'http://localhost:3020').replace(/\/$/, ''); + // Optionally include token directly in redirectUrl when env var is set (convenience for direct entry) + const includeToken = process.env.INCLUDE_TOKEN_IN_REDIRECT === '1' || process.env.INCLUDE_TOKEN_IN_REDIRECT === 'true'; + const redirectUrl = includeToken + ? `${studioBase}/?token=${encodeURIComponent(token)}&room=${encodeURIComponent(room)}&username=${encodeURIComponent(username)}` + : `${studioBase}/${id}`; + + return res.json({ + id, + studioUrl: `${studioBase}/${id}`, + redirectUrl, + ttlSeconds: ttlSec, + }); + } catch (err) { + console.error('Failed to create session', err); + return res.status(500).json({ error: String(err) }); } - - // Placeholder: return empty participants list for the requested room - return res.json({ room: { name: roomName, participants: [] } }); }); -// 404 handler -app.use((req, res) => { - res.status(404).json({ error: 'Not found' }); +app.get('/api/session/:id', async (req, res) => { + const id = req.params.id; + const s = await getSession(id); + if (!s) return res.status(404).json({ error: 'not found' }); + const ttlLeft = Math.max(0, Math.floor((s.expiresAt - Date.now()) / 1000)); + return res.json({ token: s.token, url: s.url, room: s.room, username: s.username, ttlSeconds: ttlLeft }); }); -// Error handler -app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => { +app.get('/s/:id', async (req, res) => { + const id = req.params.id; + const s = await getSession(id); + if (!s) return res.status(404).send('Not found'); + const studioBase = (process.env.VITE_STUDIO_URL || 'http://localhost:3020').replace(/\/$/, ''); + const redirectTo = `${studioBase}/studio_receiver.html?token=${encodeURIComponent(s.token)}&room=${encodeURIComponent(s.room)}&username=${encodeURIComponent(s.username)}`; + return res.redirect(302, redirectTo); +}); + +// Optional: mark session as consumed to prevent replay (single-use) +app.post('/api/session/:id/consume', async (req, res) => { + const id = req.params.id; + try { + const s = await getSession(id); + if (!s) return res.status(404).json({ error: 'not found' }); + // remove from store + if (redisClient && redisAvailable) { + await redisClient.del(`session:${id}`); + } else { + sessionStoreMemory.delete(id); + } + return res.json({ ok: true }); + } catch (err) { + console.error('Error consuming session', err); + return res.status(500).json({ error: 'failed' }); + } +}); + +app.use((_req, res) => res.status(404).json({ error: 'Not found' })); + +app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => { console.error(err.stack); res.status(500).json({ error: 'Internal server error' }); }); -app.listen(PORT, () => { - console.log(`🚀 Backend API running on http://localhost:${PORT}`); +const HOST: string = process.env.HOST ? String(process.env.HOST) : '0.0.0.0'; +app.listen(Number(PORT), HOST, () => { + console.log(`🚀 Backend API running on http://${HOST}:${PORT}`); console.log(`📡 Environment: ${process.env.NODE_ENV}`); + try { + const nets = os.networkInterfaces(); + const addresses: string[] = []; + Object.keys(nets).forEach((name) => { + const net = nets[name] || []; + net.forEach((iface: any) => { + if (iface.family === 'IPv4' && !iface.internal) addresses.push(iface.address as string); + }); + }); + if (addresses.length > 0) addresses.forEach(a => console.log(`🔗 Accessible at: http://${a}:${PORT}`)); + } catch (e) { console.warn('Could not enumerate network interfaces', e) } }); diff --git a/packages/broadcast-panel/Dockerfile b/packages/broadcast-panel/Dockerfile index 553c8fa..3b918ad 100644 --- a/packages/broadcast-panel/Dockerfile +++ b/packages/broadcast-panel/Dockerfile @@ -1,30 +1,21 @@ -# Dockerfile para Broadcast Panel +# Dockerfile for Broadcast Panel (package-local context) FROM node:20-alpine AS builder WORKDIR /app -# Copiar package files +# copy package files COPY package*.json ./ -# Instalar dependencias -RUN npm install +# install deps +RUN npm ci --no-audit --no-fund || npm install --no-audit --no-fund -# Copiar código fuente -COPY . . - -# Build +# copy source and build +COPY . ./ RUN npm run build -# Etapa de producción con nginx +# production image FROM nginx:alpine - -# Copiar build a nginx COPY --from=builder /app/dist /usr/share/nginx/html - -# Copiar configuración de nginx COPY nginx.conf /etc/nginx/conf.d/default.conf - -# Exponer puerto EXPOSE 80 - CMD ["nginx", "-g", "daemon off;"] diff --git a/packages/broadcast-panel/README.md b/packages/broadcast-panel/README.md index 5ca2877..5d41b78 100644 --- a/packages/broadcast-panel/README.md +++ b/packages/broadcast-panel/README.md @@ -144,3 +144,28 @@ Este panel sigue el patrón de diseño de **StreamYard**, caracterizado por: 3. **Consistencia:** Uso uniforme de colores, tipografía y espaciado 4. **Accesibilidad:** Contraste adecuado, tamaños de fuente legibles 5. **Responsividad:** Adaptación fluida a diferentes dispositivos + +## Entrar al estudio (token flow) + +El botón "Entrar al estudio" ahora solicita un token al servidor de tokens (configurable mediante la variable de entorno `VITE_TOKEN_SERVER_URL`) y abre el `studio-panel` enviando el token vía `postMessage` (o redirige como fallback si el popup está bloqueado). + +Variables importantes: +- VITE_TOKEN_SERVER_URL - URL base del servidor que responde en `/api/token?room=...&username=...` y devuelve JSON con `{ token, url }`. +- VITE_STUDIO_URL - URL base del `studio-panel` (ej. `https://avanzacast-studio.bfzqqk.easypanel.host`) que se usa como origin para postMessage. + +Cómo probar localmente: +1. Levanta `backend-api` con tus credenciales LiveKit (LIVEKIT_API_KEY y LIVEKIT_API_SECRET en .env): +```bash +cd packages/backend-api +npm run dev +``` +2. Arranca `broadcast-panel` (por defecto corre en http://localhost:5175): +```bash +cd packages/broadcast-panel +npm run dev +``` +3. Abre la lista de transmisiones y pulsa "Entrar al estudio" en una fila; el panel abrirá el `studio-panel` en una ventana popup y enviará el token por postMessage. + +Notas de debug: +- Si no recibes confirmación (ACK) del `studio-panel`, revisa la consola del navegador para ver posibles errores de `postMessage` (origin mismatch) o bloqueos de popup. +- Para pruebas locales puedes usar `packages/studio-panel/public/simulate_postmessage.html` (simulador) para verificar el flujo sin LiveKit. diff --git a/packages/broadcast-panel/public/dump_session.html b/packages/broadcast-panel/public/dump_session.html new file mode 100644 index 0000000..95257ed --- /dev/null +++ b/packages/broadcast-panel/public/dump_session.html @@ -0,0 +1,15 @@ + + +Dump Session + +

Session Storage Dump

+
loading...
+ + + + diff --git a/packages/broadcast-panel/public/post_token_to_studio.html b/packages/broadcast-panel/public/post_token_to_studio.html new file mode 100644 index 0000000..228a27a --- /dev/null +++ b/packages/broadcast-panel/public/post_token_to_studio.html @@ -0,0 +1,133 @@ + + +Post Token to Studio (production) + +

Post Token to Studio (production)

+
+ +
+
+ + +
+
+ +
+

+  
+
+
diff --git a/packages/broadcast-panel/scripts/simulate_ack.js b/packages/broadcast-panel/scripts/simulate_ack.js
new file mode 100644
index 0000000..e69de29
diff --git a/packages/broadcast-panel/src/components/Toast.tsx b/packages/broadcast-panel/src/components/Toast.tsx
new file mode 100644
index 0000000..df906d8
--- /dev/null
+++ b/packages/broadcast-panel/src/components/Toast.tsx
@@ -0,0 +1,20 @@
+import React from 'react'
+
+export type ToastVariant = 'info'|'success'|'error'|'warning'
+
+export function Toast({ message, variant = 'info' }: { message: string, variant?: ToastVariant }) {
+  const bg = variant === 'success' ? '#d1fae5' : variant === 'error' ? '#fee2e2' : variant === 'warning' ? '#fff7ed' : '#eef2ff'
+  const color = variant === 'success' ? '#065f46' : variant === 'error' ? '#991b1b' : variant === 'warning' ? '#92400e' : '#3730a3'
+  return (
+    
{message}
+ ) +} + +export default Toast + diff --git a/packages/broadcast-panel/src/components/TransmissionsTable.tsx b/packages/broadcast-panel/src/components/TransmissionsTable.tsx index 775f13e..ff3472a 100644 --- a/packages/broadcast-panel/src/components/TransmissionsTable.tsx +++ b/packages/broadcast-panel/src/components/TransmissionsTable.tsx @@ -7,6 +7,7 @@ import styles from './TransmissionsTable.module.css' import InviteGuestsModal from './InviteGuestsModal' import { NewTransmissionModal } from '@shared/components' import type { Transmission } from '@shared/types' +import useStudioLauncher from '../hooks/useStudioLauncher' interface Props { transmissions: Transmission[] @@ -20,15 +21,17 @@ const platformIcons: Record = { 'Facebook': , 'Twitch': , 'LinkedIn': , - 'Genérico': , // Logo genérico para transmisiones sin destino + 'Generico': , // Logo genérico para transmisiones sin destino } -const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate, isLoading }) => { +const TransmissionsTable: React.FC = (props) => { + const { transmissions, onDelete, onUpdate, isLoading } = props const [activeTab, setActiveTab] = useState<'upcoming' | 'past'>('upcoming') const [inviteOpen, setInviteOpen] = useState(false) const [inviteLink, setInviteLink] = useState(undefined) const [editOpen, setEditOpen] = useState(false) const [editTransmission, setEditTransmission] = useState(undefined) + const { openStudio, loadingId: launcherLoadingId, error: launcherError } = useStudioLauncher() const [loadingId, setLoadingId] = useState(null) const handleEdit = (t: Transmission) => { @@ -37,7 +40,7 @@ const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate } // Filtrado por fechas - const filtered = transmissions.filter(t => { + const filtered = transmissions.filter((t: Transmission) => { // Si es "Próximamente" o no tiene fecha programada, siempre va a "upcoming" if (!t.scheduled || t.scheduled === 'Próximamente') return activeTab === 'upcoming' @@ -52,44 +55,20 @@ const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate }) const openStudioForTransmission = async (t: Transmission) => { - if (loadingId) return + if (loadingId || launcherLoadingId) return setLoadingId(t.id) try { const userRaw = localStorage.getItem('avanzacast_user') || 'Demo User' - const user = encodeURIComponent(userRaw) - const room = encodeURIComponent(t.id || 'avanzacast-studio') - - console.log('[BroadcastPanel] Solicitando token:', { room: decodeURIComponent(room), user: decodeURIComponent(user) }) - - const TOKEN_SERVER = import.meta.env.VITE_TOKEN_SERVER_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host' - const tokenUrl = `${TOKEN_SERVER.replace(/\/$/, '')}/api/token?room=${room}&username=${user}` - const tokenRes = await fetch(tokenUrl) - if (!tokenRes.ok) throw new Error('No se pudo obtener token') - const tokenData = await tokenRes.json() - - console.log('[BroadcastPanel] Token recibido:', { - tokenLength: tokenData.token?.length || 0, - serverUrl: tokenData.serverUrl, - hasToken: !!tokenData.token, - hasServerUrl: !!tokenData.serverUrl - }) - - // Pasar solo token, room y user por URL (serverUrl se lee del .env en studio-panel) - const params = new URLSearchParams({ - token: tokenData.token, - room: decodeURIComponent(room), - user: decodeURIComponent(user) - }) - - console.log('[BroadcastPanel] Redirigiendo con parámetros en URL...') - - // Redirigir a studio-panel en la misma pestaña con los datos en la URL - const STUDIO_URL = import.meta.env.VITE_STUDIO_URL || 'https://avanzacast-studio.bfzqqk.easypanel.host' - const shortId = Math.random().toString(36).slice(2, 10) - window.location.href = `${STUDIO_URL.replace(/\/$/, '')}/${shortId}?${params.toString()}` - } catch (err) { + const user = (userRaw) + const room = (t.id || 'avanzacast-studio') + const result = await openStudio({ room, username: user }) + if (!result) { + throw new Error('No se pudo abrir el estudio') + } + setLoadingId(null) + } catch (err: any) { console.error('[BroadcastPanel] Error entrando al estudio:', err) - alert('No fue posible entrar al estudio. Revisa el servidor de tokens.') + alert(err?.message || 'No fue posible entrar al estudio. Revisa el servidor de tokens.') setLoadingId(null) } } @@ -148,7 +127,7 @@ const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate - {filtered.map(t => ( + {filtered.map((t: Transmission) => (
@@ -158,7 +137,7 @@ const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate
{t.title}
- {t.platform === 'Genérico' ? 'Solo grabación' : (t.platform || 'YouTube')} + {t.platform === 'Generico' ? 'Solo grabación' : (t.platform || 'YouTube')}
@@ -178,20 +157,23 @@ const TransmissionsTable: React.FC = ({ transmissions, onDelete, onUpdate + + {launcherError && ( +
{launcherError}
+ )} } diff --git a/packages/broadcast-panel/src/hooks/useStudioLauncher.ts b/packages/broadcast-panel/src/hooks/useStudioLauncher.ts new file mode 100644 index 0000000..3b23eb9 --- /dev/null +++ b/packages/broadcast-panel/src/hooks/useStudioLauncher.ts @@ -0,0 +1,178 @@ +import { useState } from 'react' + +export type OpenStudioOptions = { + room: string + username: string + ttl?: number +} + +type SessionData = { + studioUrl?: string + redirectUrl?: string + token?: string + room?: string + ttl?: number +} + +export default function useStudioLauncher() { + const [loadingId, setLoadingId] = useState(null) + const [error, setError] = useState(null) + + async function openStudio(opts: OpenStudioOptions) { + const { room, username, ttl } = opts + if (!room || !username) { + setError('room and username are required') + return null + } + setError(null) + setLoadingId(room) + + // Timeouts and retry config + const POST_MESSAGE_TIMEOUT = 5000 // ms + const POST_MESSAGE_INTERVAL = 300 // ms + + try { + const TOKEN_SERVER = (import.meta.env.VITE_TOKEN_SERVER_URL as string) || 'https://avanzacast-servertokens.bfzqqk.easypanel.host' + const sessionUrl = `${TOKEN_SERVER.replace(/\/$/, '')}/api/session` + + // Try to open a blank popup immediately (in direct response to user action) to reduce popup-blocker issues + let popup: Window | null = null + try { + popup = window.open('about:blank', '_blank', 'noopener,noreferrer') + } catch (e) { + popup = null + } + + // If popup failed to open, we will fallback to redirect later + + const sessionRes = await fetch(sessionUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ room, username, ttl }) + }) + if (!sessionRes.ok) { + const txt = await sessionRes.text().catch(() => '') + const msg = `No se pudo crear la sesión (${sessionRes.status}) ${txt}` + console.error('[useStudioLauncher]', msg) + setError(msg) + setLoadingId(null) + // Close popup if we opened it but will not navigate it + try { popup?.close() } catch (e) { /* ignore */ } + return null + } + const sessionData: SessionData = await sessionRes.json() + + const studioUrl = sessionData.studioUrl || sessionData.redirectUrl || null + if (!studioUrl) { + const msg = 'No studio URL returned from token server' + console.error('[useStudioLauncher]', msg) + setError(msg) + setLoadingId(null) + try { popup?.close() } catch (e) { /* ignore */ } + return null + } + + const targetUrl = sessionData.studioUrl || sessionData.redirectUrl || studioUrl + + // If popup couldn't be opened, fallback to redirecting current window to redirectUrl (may contain token) + if (!popup) { + try { + const fallback = sessionData.redirectUrl || targetUrl + window.location.href = fallback + setLoadingId(null) + return sessionData + } catch (e) { + // can't redirect, return error + const msg = 'No se pudo abrir popup ni redirigir' + (String(e) || '') + console.error('[useStudioLauncher]', msg) + setError(msg) + setLoadingId(null) + return null + } + } + + // We have a popup window. Navigate it to the studio (without token in URL if possible) + try { + popup.location.href = targetUrl + } catch (e) { + // Some browsers may block setting location for cross-origin until navigation happens + try { popup.location.assign(targetUrl) } catch (e2) { /* ignore */ } + } + + // Prepare message to send the token + const msgPayload = { type: 'LIVEKIT_TOKEN', token: sessionData.token, room: sessionData.room } + const targetOrigin = (() => { + try { return new URL(targetUrl).origin } catch (e) { return '*' } + })() + + let posted = false + let ackReceived = false + + // Listen for ACK from the studio window + function onMessage(e: MessageEvent) { + try { + const d = e.data || {} + if (d?.type === 'LIVEKIT_ACK' && d?.room === sessionData.room) { + ackReceived = true + // optional: we can close the popup opener listener + window.removeEventListener('message', onMessage) + } + } catch (err) { + // ignore malformed messages + } + } + window.addEventListener('message', onMessage) + + const start = Date.now() + // Try posting repeatedly until timeout or ACK + while (!posted && Date.now() - start < POST_MESSAGE_TIMEOUT && !ackReceived) { + try { + // postMessage itself doesn't throw for cross-origin; we still wrap it + popup.postMessage(msgPayload, targetOrigin) + posted = true // assume success; ack will confirm + } catch (e) { + // ignore and retry + } + if (!posted) await new Promise((r) => setTimeout(r, POST_MESSAGE_INTERVAL)) + } + + // If we posted but didn't receive ACK, try a short wait for ack + const waitForAck = () => new Promise((resolve) => { + const maxWait = 2000 + const t0 = Date.now() + const int = setInterval(() => { + if (ackReceived || Date.now() - t0 > maxWait) { + clearInterval(int) + resolve() + } + }, 100) + }) + + if (posted) { + await waitForAck() + } + + // If we couldn't post at all or no ACK received, fallback to redirect to redirectUrl (may include token) + if (!posted || (!ackReceived && sessionData.redirectUrl)) { + try { + // navigate popup to redirectUrl which typically contains token + const fallback = sessionData.redirectUrl || targetUrl + popup.location.href = fallback + } catch (e) { + // If navigation fails, try to navigate the current window + try { window.location.href = sessionData.redirectUrl || targetUrl } catch (e2) { /* ignore */ } + } + } + + setLoadingId(null) + return sessionData + } catch (err: any) { + console.error('[useStudioLauncher] error opening studio', err) + setError(String(err?.message || err)) + setLoadingId(null) + return null + } + } + + return { openStudio, loadingId, error } +} diff --git a/packages/broadcast-panel/src/hooks/useToast.tsx b/packages/broadcast-panel/src/hooks/useToast.tsx new file mode 100644 index 0000000..f32b9c0 --- /dev/null +++ b/packages/broadcast-panel/src/hooks/useToast.tsx @@ -0,0 +1,44 @@ +import React, { createContext, useContext, useState, useEffect } from 'react' +import Toast from '../components/Toast' + +type ToastItem = { id: string, message: string, variant?: 'info'|'success'|'error'|'warning' } + +const ToastContext = createContext<{ show: (m: string, v?: ToastItem['variant']) => void } | undefined>(undefined) + +export function ToastProvider({ children }: { children: React.ReactNode }) { + const [list, setList] = useState([]) + + function show(message: string, variant: ToastItem['variant'] = 'info') { + const id = Math.random().toString(36).slice(2,9) + setList(l => [...l, { id, message, variant }]) + setTimeout(() => setList(l => l.filter(x => x.id !== id)), 5000) + } + + useEffect(() => { + function onGlobal(e: Event) { + try { + const ce = e as CustomEvent + if (!ce?.detail) return + const { message, variant } = ce.detail as any + if (message) show(message, variant) + } catch (err) {} + } + window.addEventListener('AVZ_TOAST', onGlobal as EventListener) + return () => window.removeEventListener('AVZ_TOAST', onGlobal as EventListener) + }, []) + + return ( + + {children} +
+ {list.map(i => )} +
+
+ ) +} + +export function useToast() { + const ctx = useContext(ToastContext) + if (!ctx) throw new Error('useToast must be used within ToastProvider') + return ctx +} diff --git a/packages/broadcast-panel/src/main.tsx b/packages/broadcast-panel/src/main.tsx index 369acbe..3528ba2 100644 --- a/packages/broadcast-panel/src/main.tsx +++ b/packages/broadcast-panel/src/main.tsx @@ -2,6 +2,11 @@ import React from 'react' import { createRoot } from 'react-dom/client' import PageContainer from './components/PageContainer' import './styles.css' +import { ToastProvider } from './hooks/useToast' const root = createRoot(document.getElementById('root')!) -root.render() +root.render( + + + +) diff --git a/packages/broadcast-panel/src/utils/studioLauncher.ts b/packages/broadcast-panel/src/utils/studioLauncher.ts new file mode 100644 index 0000000..2330310 --- /dev/null +++ b/packages/broadcast-panel/src/utils/studioLauncher.ts @@ -0,0 +1,100 @@ +export interface StudioTokenPayload { + token: string + serverUrl?: string + room?: string + user?: string +} + +export async function openStudioWithToken(tokenData: StudioTokenPayload, opts?: { studioUrl?: string, shortIdLength?: number, onAck?: (ack: any) => void, forceRedirect?: boolean }) { + const STUDIO_URL = opts?.studioUrl || (import.meta.env.VITE_STUDIO_URL as string) || 'https://avanzacast-studio.bfzqqk.easypanel.host' + const shortId = Math.random().toString(36).slice(2, 2 + (opts?.shortIdLength || 8)) + const studioBase = STUDIO_URL.replace(/\/$/, '') + const studioPath = `${studioBase}/${shortId}` + + const payload = { + type: 'LIVEKIT_TOKEN', + token: tokenData.token, + url: tokenData.serverUrl || (import.meta.env.VITE_LIVEKIT_URL as string) || '', + room: tokenData.room || '', + user: tokenData.user || '', + } + + const paramsForFallback = () => { + const p = new URLSearchParams({ token: tokenData.token || '', room: tokenData.room || '', username: tokenData.user || '' }) + if (tokenData.serverUrl) p.set('serverUrl', tokenData.serverUrl) + return p.toString() + } + + const forceRedirectEnv = (import.meta.env.VITE_FORCE_STUDIO_REDIRECT as string) || '' + const forceRedirect = opts?.forceRedirect !== undefined ? opts.forceRedirect : (forceRedirectEnv === '0' ? false : true) + + try { + if (forceRedirect) { + const q = paramsForFallback() + window.location.href = `${studioPath}?${q}` + return + } + + const originAllowed = (() => { + try { return new URL(STUDIO_URL).origin } catch { return '*' } + })() + + try { + const win = window.open(studioPath, '_blank') + if (win) { + let ackTimeout: number | null = null + const ackListener = (e: MessageEvent) => { + try { + if (!e?.data) return + const d = e.data + if (d?.type === 'LIVEKIT_ACK') { + try { opts?.onAck?.(d) } catch (err) { console.error('onAck callback error', err) } + if (!opts?.onAck) { + window.dispatchEvent(new CustomEvent('AVZ_TOAST', { detail: { message: d.status === 'connected' ? 'Studio conectado' : `Studio error: ${d?.error || d?.status}`, variant: d.status === 'connected' ? 'success' : 'error' } })) + } + if (ackTimeout) { clearTimeout(ackTimeout); ackTimeout = null } + window.removeEventListener('message', ackListener as unknown as EventListener) + } + } catch (err) { console.error('[studioLauncher] ackListener error', err) } + } + + window.addEventListener('message', ackListener as unknown as EventListener) + + ackTimeout = window.setTimeout(() => { + try { + window.removeEventListener('message', ackListener as unknown as EventListener) + if (!opts?.onAck) { + window.dispatchEvent(new CustomEvent('AVZ_TOAST', { detail: { message: 'No se recibió confirmación del Studio', variant: 'warning' } })) + } + } catch (err) { console.error('[studioLauncher] ack timeout cleanup error', err) } + }, 20000) + + const post = () => { + try { + win.postMessage(payload, originAllowed) + console.debug('[studioLauncher] postMessage ->', originAllowed) + } catch (err) { + try { (win as any).postMessage(payload, '*') } catch (err2) { console.error('[studioLauncher] postMessage failed', err2) } + } + } + + setTimeout(post, 300) + setTimeout(post, 800) + setTimeout(post, 1500) + return + } + + // popup blocked -> fallback to redirect + const q = paramsForFallback() + window.location.href = `${studioPath}?${q}` + } catch (err) { + console.error('[studioLauncher] Error opening studio panel, fallback to redirect', err) + const q = paramsForFallback() + window.location.href = `${studioPath}?${q}` + } + } catch (err) { + console.error('[studioLauncher] Unexpected error', err) + } +} + +export default openStudioWithToken diff --git a/packages/landing-page/postcss.config.cjs b/packages/landing-page/postcss.config.cjs index 9bc2f2d..f5de1c1 100644 --- a/packages/landing-page/postcss.config.cjs +++ b/packages/landing-page/postcss.config.cjs @@ -1,6 +1,18 @@ module.exports = { - plugins: { - 'tailwindcss': {}, - 'autoprefixer': {}, - }, + plugins: (() => { + // Tailwind v4 changed the PostCSS plugin distribution to @tailwindcss/postcss + // Try to require it first, otherwise fall back to the older 'tailwindcss' package name + let tailwindPlugin + try { + tailwindPlugin = require('@tailwindcss/postcss') + } catch (e) { + // fallback for environments still using the legacy package name + tailwindPlugin = require('tailwindcss') + } + + return { + [tailwindPlugin.name || 'tailwindcss']: tailwindPlugin(), + autoprefixer: {}, + } + })(), } diff --git a/packages/studio-panel/.dockerignore b/packages/studio-panel/.dockerignore new file mode 100644 index 0000000..bd79bcd --- /dev/null +++ b/packages/studio-panel/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +npm-debug.log +Dockerfile +.dockerignore +.vscode +.git +.gitignore + diff --git a/packages/studio-panel/Dockerfile b/packages/studio-panel/Dockerfile new file mode 100644 index 0000000..0df39e0 --- /dev/null +++ b/packages/studio-panel/Dockerfile @@ -0,0 +1,28 @@ +# Multi-stage Dockerfile: build with Node, serve with Nginx +# Build stage +FROM node:20-alpine AS builder +WORKDIR /app +# Install build deps +# Copy package files and workspace packages to allow local file:../avanza-ui resolution +COPY package.json package-lock.json* ./ +# Copy entire monorepo so file: references work (keeps things simple) +COPY .. /app + +WORKDIR /app/packages/studio-panel +RUN npm ci --no-audit --no-fund && npm run build + +# Production stage +FROM nginx:stable-alpine +# Remove default nginx static +RUN rm -rf /usr/share/nginx/html/* + +# Copy built static files +COPY --from=builder /app/packages/studio-panel/dist /usr/share/nginx/html + +# Copy custom nginx config if provided (optional) +# If deploy/nginx.avanzacast.conf exists, use it as default.conf +COPY packages/studio-panel/deploy/nginx.avanzacast.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] + diff --git a/packages/studio-panel/README.DOCKER.md b/packages/studio-panel/README.DOCKER.md new file mode 100644 index 0000000..2c811ab --- /dev/null +++ b/packages/studio-panel/README.DOCKER.md @@ -0,0 +1,70 @@ +# Docker build & deploy for studio-panel + +This file explains how to build the `studio-panel` Docker image locally and produce a deployable artifact. + +Prerequisites +- Docker installed and running on the host. +- Node.js and npm (for local build path if you prefer building before docker). If you use Docker multi-stage, Node is not needed locally. + +Quick build steps (preferred: multi-stage Docker build) + +From repo root or inside `packages/studio-panel`: + +```bash +# from repo root +cd packages/studio-panel +# build docker (multi-stage uses npm inside builder stage) +docker build -t avanzacast/studio-panel:latest . + +# run locally to test +docker run --rm -it -p 3020:80 avanzacast/studio-panel:latest + +# now test with curl +curl -I http://localhost:3020/ +``` + +Notes +- The Dockerfile is multi-stage: the builder stage runs `npm ci` and `npm run build` inside the container. The built `dist/` is copied to nginx in the final image. +- The Dockerfile copies the entire monorepo into the builder context to allow `file:../avanza-ui` dependency to be resolved during container build. + +If the build fails inside Docker due to strict network or registry errors, you can build locally first and then use a simpler Dockerfile that only copies the `dist/` folder into the nginx image: + +Local-build alternative: + +```bash +# build locally +cd packages/studio-panel +npm ci +npm run build + +# create a simple nginx image +cd packages/studio-panel +cat > Dockerfile.simple <<'EOF' +FROM nginx:stable-alpine +COPY dist /usr/share/nginx/html +COPY deploy/nginx.avanzacast.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] +EOF + +docker build -f Dockerfile.simple -t avanzacast/studio-panel:local . +``` + +If you want the tarball artifact to deploy on the server, run: + +```bash +# after successful build and image creation +IMAGE=avanzacast/studio-panel:latest +docker save $IMAGE -o /tmp/studio-panel-image-$(date +%s).tar +# scp that tar to the server and on server run: +# docker load -i studio-panel-image-.tar +# docker run -d --name studio-panel -p 80:80 avanzacast/studio-panel:latest +``` + +Troubleshooting +- If the multi-stage build cannot resolve `file:../avanza-ui`, ensure the entire repository is in the build context (we copy `..` into the builder in the current Dockerfile). If your Docker setup restricts context size, prefer local build + `Dockerfile.simple`. +- Inspect build logs with: + - `docker build --progress=plain -t avanzacast/studio-panel:local .` + - `docker logs ` for runtime errors. + + diff --git a/packages/studio-panel/README.E2E.md b/packages/studio-panel/README.E2E.md new file mode 100644 index 0000000..8fe6afc --- /dev/null +++ b/packages/studio-panel/README.E2E.md @@ -0,0 +1,34 @@ +# E2E Playwright tests - Studio Panel + +This guide explains how to run the Playwright E2E tests locally and in CI. The tests simulate Broadcast -> Token Server -> Studio flows and produce logs and screenshots for debugging. + +Local quick run + +```bash +cd packages/studio-panel +# optional: install playwright locally +npm install --no-audit --no-fund --no-save playwright +npx playwright install --with-deps +# run the helper script (installs playwright if missing and runs the test) +chmod +x run_playwright_test.sh +./run_playwright_test.sh + +# After run, check artifacts: +ls -lh /tmp/playwright_debug.log /tmp/playwright_run_output.log +ls -lh /tmp/sim_postmessage_simulator.png /tmp/sim_postmessage_studio.png +``` + +CI (GitHub Actions) + +A workflow has been added at `.github/workflows/e2e-playwright.yml`. It can be triggered from the Actions tab or via `workflow_dispatch`. + +Set these repository secrets to override target URLs (optional): +- `BROADCAST_URL` - e.g. `https://avanzacast-broadcastpanel.bfzqqk.easypanel.host/post_token_to_studio.html?auto=1` +- `STUDIO_ORIGIN` - e.g. `https://avanzacast-studio.bfzqqk.easypanel.host` + +The workflow will upload logs and screenshots as artifacts for download. + +Troubleshooting +- If Playwright fails to install browsers on runners, try `npx playwright install --with-deps` locally to debug. +- If tests time out, increase timeouts in `scripts/playwright_postmessage_test.mjs`. + diff --git a/packages/studio-panel/build_and_pack_docker.sh b/packages/studio-panel/build_and_pack_docker.sh new file mode 100755 index 0000000..a196fb4 --- /dev/null +++ b/packages/studio-panel/build_and_pack_docker.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "$0")" && pwd) +cd "$ROOT_DIR" + +echo "[1/5] Installing dependencies" +npm ci + +echo "[2/5] Running Vite build" +npm run build + +echo "[3/5] Creating Dockerfile.simple and building image" +cat > Dockerfile.simple <<'EOF' +FROM nginx:stable-alpine +COPY dist /usr/share/nginx/html +COPY deploy/nginx.avanzacast.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] +EOF + +IMAGE_TAG="avanzacast/studio-panel:local" +docker build -f Dockerfile.simple -t "$IMAGE_TAG" . + +TS=$(date +%s) +OUT=/tmp/studio-panel-image-${TS}.tar + +echo "[4/5] Saving docker image to $OUT" +docker save "$IMAGE_TAG" -o "$OUT" + +echo "[5/5] Done. Image saved to: $OUT" +ls -lh "$OUT" + +# keep the artifact path for caller +echo "$OUT" + diff --git a/packages/studio-panel/deploy/nginx.avanzacast.conf b/packages/studio-panel/deploy/nginx.avanzacast.conf new file mode 100644 index 0000000..9eac2bc --- /dev/null +++ b/packages/studio-panel/deploy/nginx.avanzacast.conf @@ -0,0 +1,53 @@ +# Dev nginx config for avanzacast-studio (non-SSL) +server { + listen 80; + server_name avanzacast-studio.bfzqqk.easypanel.host; + + # Proxy to Vite dev server (HTTP) + location / { + proxy_pass http://127.0.0.1:3020; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + proxy_set_header X-Forwarded-Host $host; + } + + # Optional: serve static built files if you run `npm run build` and serve from dist + location /static/ { + alias /home/xesar/Documentos/Nextream/AvanzaCast/packages/studio-panel/dist/; + } + + # Increase timeouts + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; +} + +# Also keep a plain HTTP server for broadcast and token-server (reverse-proxy uses root default.conf too) +server { + listen 80; + server_name avanzacast-broadcastpanel.bfzqqk.easypanel.host; + location / { + proxy_pass http://broadcast-panel:5175; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +server { + listen 80; + server_name avanzacast-servertokens.bfzqqk.easypanel.host; + location / { + proxy_pass http://backend-api:4000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/packages/studio-panel/deploy/studio-panel.service b/packages/studio-panel/deploy/studio-panel.service new file mode 100644 index 0000000..e2c0719 --- /dev/null +++ b/packages/studio-panel/deploy/studio-panel.service @@ -0,0 +1,16 @@ +[Unit] +Description=AvanzaCast Studio Panel (Vite dev) +After=network.target + +[Service] +Type=simple +User=youruser +WorkingDirectory=/home/xesar/Documentos/Nextream/AvanzaCast/packages/studio-panel +Environment=NODE_ENV=development +ExecStart=/usr/bin/npm run dev +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target + diff --git a/packages/studio-panel/e2e/playwright.config.js b/packages/studio-panel/e2e/playwright.config.js new file mode 100644 index 0000000..7b76073 --- /dev/null +++ b/packages/studio-panel/e2e/playwright.config.js @@ -0,0 +1,6 @@ +// minimal Playwright config for local E2E +module.exports = { + use: { headless: true }, + timeout: 30_000, +}; + diff --git a/packages/studio-panel/e2e/playwright_test.mjs b/packages/studio-panel/e2e/playwright_test.mjs new file mode 100644 index 0000000..e4e62ea --- /dev/null +++ b/packages/studio-panel/e2e/playwright_test.mjs @@ -0,0 +1,81 @@ +#!/usr/bin/env node +// Playwright E2E test for Studio Panel (automates Broadcast -> Studio flow) +import fetch from 'node-fetch'; +import fs from 'fs'; +import { chromium } from 'playwright'; + +const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; +const STUDIO_BASE = process.env.STUDIO_URL || 'http://localhost:3020'; +const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 30000); + +function log(...args) { console.log(new Date().toISOString(), ...args); } + +async function createSession() { + log('POST /api/session ->', TOKEN_SERVER); + const res = await fetch(`${TOKEN_SERVER}/api/session`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ room: 'e2e-room', username: 'pw-runner' }) + }); + const body = await res.json(); + log('session response', res.status, body); + if (!res.ok) throw new Error('session creation failed'); + return body; +} + +(async () => { + try { + const session = await createSession(); + const studioUrl = session.redirectUrl || session.studioUrl || (session.id ? `${STUDIO_BASE}/${session.id}` : null); + if (!studioUrl) throw new Error('No studio url returned'); + + log('Launching browser'); + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + + log('Opening', studioUrl); + const resp = await page.goto(studioUrl, { waitUntil: 'domcontentloaded', timeout: TIMEOUT }); + log('opened status', resp && resp.status()); + + // Wait for either a #status element or a known text + try { + const status = page.locator('#status'); + await status.waitFor({ timeout: 7000 }); + const txt = await status.textContent(); + log('#status text:', txt && txt.slice(0,200)); + } catch (e) { + log('No #status or timeout, trying heuristics'); + // look for explicit token string in page content + const content = await page.content(); + if (content.includes('Token recibido') || content.includes('LIVEKIT_TOKEN') || content.includes(session.token || '')) { + log('Token text appears in page content'); + } else { + log('Token not obviously present in page content'); + } + } + + const s1 = '/tmp/pw_e2e_studio_' + Date.now() + '.png'; + await page.screenshot({ path: s1, fullPage: true }); + log('Saved screenshot', s1); + + // Also fetch session via API to assert token present + if (session.id) { + try { + const lookup = await fetch(`${TOKEN_SERVER}/api/session/${session.id}`); + const j = await lookup.json(); + log('session lookup', lookup.status, Object.keys(j)); + const sessionFile = `/tmp/session_${session.id}.json`; + fs.writeFileSync(sessionFile, JSON.stringify(j, null, 2)); + log('Saved session JSON to', sessionFile); + } catch (err) { log('session lookup failed', err.message) } + } + + await browser.close(); + log('E2E success'); + process.exit(0); + } catch (err) { + console.error('E2E error', err.message); + process.exit(1); + } +})(); + diff --git a/packages/studio-panel/e2e/run_e2e.mjs b/packages/studio-panel/e2e/run_e2e.mjs new file mode 100644 index 0000000..a220864 --- /dev/null +++ b/packages/studio-panel/e2e/run_e2e.mjs @@ -0,0 +1,147 @@ +import { chromium } from 'playwright'; +import { spawn } from 'child_process'; +import path from 'path'; + +console.log('run_e2e: starting (pid=' + process.pid + ')'); +console.log('ENV VITE_STUDIO_URL=' + (process.env.VITE_STUDIO_URL || '')); +console.log('ENV VITE_BROADCASTPANEL_URL=' + (process.env.VITE_BROADCASTPANEL_URL || '')); +console.log('ENV VITE_TOKEN_SERVER_URL=' + (process.env.VITE_TOKEN_SERVER_URL || '')); + +const serverPath = path.resolve('./server.mjs'); +const base = 'http://localhost:5174'; + +// Allow overriding the target origin via ENV (e.g., VITE_STUDIO_URL) +const targetOrigin = process.env.VITE_STUDIO_URL || process.env.TARGET_ORIGIN || ''; +// If provided, open this as the sender page so origin matches allowed production origins +const broadcastSender = process.env.VITE_BROADCASTPANEL_URL || ''; +// Token server URL for obtaining tokens automatically +const tokenServer = process.env.VITE_TOKEN_SERVER_URL || process.env.TOKEN_SERVER_URL || ''; + +async function startServer() { + console.log('run_e2e: starting static server at', serverPath); + const proc = spawn(process.execPath, [serverPath], { env: { ...process.env, PORT: '5174' }, stdio: ['ignore', 'pipe', 'pipe'] }); + proc.stdout.on('data', d => process.stdout.write('[server] ' + d.toString())); + proc.stderr.on('data', d => process.stderr.write('[server] ' + d.toString())); + await new Promise(r => setTimeout(r, 300)); + console.log('run_e2e: static server started'); + return proc; +} + +// helper: request token from token server +async function requestTokenFromServer() { + if (!tokenServer) return null; + try { + // If SESSION_ID is provided, request that session; otherwise use a default /api/session/e2e endpoint + const sessionId = process.env.SESSION_ID || ''; + const endpoint = sessionId ? `/api/session/${encodeURIComponent(sessionId)}` : '/api/session/e2e'; + const url = `${tokenServer.replace(/\/$/, '')}${endpoint}`; + console.log('Requesting token from', url, sessionId ? `(sessionId=${sessionId})` : '(default)'); + const res = await fetch(url, { method: 'GET' }); + if (!res.ok) { + console.warn('Token server returned', res.status); + return null; + } + const data = await res.json(); + if (data && data.token) return data; + return null; + } catch (err) { + console.warn('Token request failed:', String(err)); + return null; + } +} + +async function run() { + console.log('run_e2e: launching browser'); + const server = await startServer(); + const browser = await chromium.launch({ headless: true }); + console.log('run_e2e: browser launched'); + const context = await browser.newContext(); + const page = await context.newPage(); + + let url; + if (broadcastSender) { + url = broadcastSender; // open prod broadcast panel as sender + console.log('Opening broadcast sender at', url); + } else { + url = base + '/sender.html'; + if (targetOrigin) url += '?target=' + encodeURIComponent(targetOrigin); + console.log('Opening local sender at', url); + } + + console.log('run_e2e: navigating to', url); + await page.goto(url); + console.log('run_e2e: page loaded'); + + // If we opened local sender, click UI; if we opened remote broadcast page we try to trigger postMessage via evaluate + if (!broadcastSender) { + await page.click('#open'); + } + + // Before sending a token, try to fetch a fresh token from the token server + let token = 'E2E_TEST_TOKEN'; // fallback + let tokenMeta = null; + try { + tokenMeta = await requestTokenFromServer(); + if (tokenMeta && tokenMeta.token) { + token = tokenMeta.token; + console.log('Obtained token from server, using it for handshake'); + } else { + console.log('No token from server, using fallback token'); + } + } catch (e) { + console.warn('Token fetch error, using fallback token', e); + } + + if (!broadcastSender) { + // send token from the local sender UI (click send) + await page.click('#send'); + // but override the message in the page to use the token we fetched + try { + await page.evaluate((tok) => { + if (window.__studioPopup && !window.__studioPopup.closed) { + try { + window.__studioPopup.postMessage({ type: 'LIVEKIT_TOKEN', token: tok, room: 'e2e-room' }, window.__studioPopup.location?.origin || '*'); + } catch (e) { + // fallback: send to global origin used by the page + try { window.postMessage({ type: 'LIVEKIT_TOKEN', token: tok, room: 'e2e-room' }, location.origin); } catch(e){} + } + } + }, token); + } catch (e) { console.warn('Override send failed', e); } + } else { + // For remote broadcast panel, open the studio popup and post message using the fetched token + await page.evaluate(async (studioUrl, tok) => { + // open popup + window.popupForE2E = window.open(studioUrl, 'studioPopup', 'width=800,height=600'); + // wait for a moment and then post the token + await new Promise(r => setTimeout(r, 600)); + try { + window.popupForE2E.postMessage({ type: 'LIVEKIT_TOKEN', token: tok, room: 'e2e-room' }, studioUrl); + } catch (e) { + console.error('postMessage failed inside page eval', e); + } + }, targetOrigin || '', token); + } + + // wait for token ack + await page.waitForFunction(() => { + const p = document.querySelector('pre'); + return p && p.textContent && p.textContent.includes('LIVEKIT_TOKEN_ACK'); + }, { timeout: 7000 }).catch(()=>{}); + + // wait for connected ack + await page.waitForFunction(() => { + const p = document.querySelector('pre'); + return p && p.textContent && p.textContent.includes('LIVEKIT_ACK') && p.textContent.includes('connected'); + }, { timeout: 7000 }).catch(()=>{}); + + console.log('run_e2e: finished script, collecting logs'); + const log = await page.$eval('pre', el => el.textContent).catch(()=>''); + console.log('E2E log:\n', log); + + await browser.close(); + console.log('run_e2e: browser closed, killing server'); + server.kill(); +} + +run().catch(err => { console.error('run_e2e: fatal error', err); process.exit(1); }); diff --git a/packages/studio-panel/e2e/selectors_streamyard.json b/packages/studio-panel/e2e/selectors_streamyard.json new file mode 100644 index 0000000..3d704e2 --- /dev/null +++ b/packages/studio-panel/e2e/selectors_streamyard.json @@ -0,0 +1,103 @@ +{ + "source": "streamyard.com broadcasts -> studio", + "capturedAt": "2025-11-15T00:00:00Z", + "notes": "Selectores heurísticos y alternativas (texto, xpath, css) para pruebas E2E. Usar la estrategia text (Playwright) o XPath cuando el texto es estable.", + "selectors": [ + { + "id": "broadcasts.enter_studio_link", + "description": "Link 'Entrar al estudio' en la tabla de broadcasts (fila de transmisión)", + "playwright": "text=Entrar al estudio", + "css": "a:has-text('Entrar al estudio')", + "xpath": "//a[contains(normalize-space(.), 'Entrar al estudio')]", + "page": "broadcasts" + }, + { + "id": "prejoin.start_camera_button", + "description": "Botón para iniciar la cámara en la pantalla previa al ingreso", + "playwright": "text=Iniciar cámara", + "css": "button:has-text('Iniciar cámara')", + "xpath": "//button[contains(normalize-space(.), 'Iniciar cámara')]", + "page": "studio-prejoin" + }, + { + "id": "prejoin.join_without_devices", + "description": "Botón fallback 'Entrar sin micrófono/cámara' cuando no hay dispositivos", + "playwright": "text=Entrar sin micrófono/cámara", + "css": "button:has-text('Entrar sin micrófono/cámara')", + "xpath": "//button[contains(normalize-space(.), 'Entrar sin micrófono/cámara')]", + "page": "studio-prejoin" + }, + { + "id": "prejoin.enter_studio_button", + "description": "Botón final 'Entrar al estudio' en prejoin (si existe)", + "playwright": "text=Entrar al estudio", + "css": "button:has-text('Entrar al estudio'), a:has-text('Entrar al estudio')", + "xpath": "//button[contains(normalize-space(.), 'Entrar al estudio')] | //a[contains(normalize-space(.), 'Entrar al estudio')]", + "page": "studio-prejoin" + }, + { + "id": "studio.add_guest_button", + "description": "Botón 'Agregar invitados' en el panel del estudio (green room)", + "playwright": "text=Agregar invitados", + "css": "button:has-text('Agregar invitados')", + "xpath": "//button[contains(normalize-space(.), 'Agregar invitados')]", + "page": "studio" + }, + { + "id": "studio.record_button", + "description": "Botón 'Grabar' o 'Record' en la barra de control para iniciar/detener grabación", + "playwright": "text=Grabar", + "css": "button:has-text('Grabar'), button:has-text('Record'), button:has-text('Iniciar grabación'), button:has-text('Start Recording'), button:has-text('Recording'), button[data-testid*='record']", + "xpath": "//button[contains(normalize-space(.), 'Grabar') or contains(normalize-space(.), 'Record') or contains(normalize-space(.), 'Iniciar grabación') or contains(normalize-space(.), 'Start Recording') or contains(normalize-space(.), 'Recording')]", + "page": "studio" + }, + { + "id": "studio.destination_button", + "description": "Botón 'Agregar destino' (configuración de plataformas de multistream)", + "playwright": "text=Agregar destino", + "css": "button:has-text('Agregar destino')", + "xpath": "//button[contains(normalize-space(.), 'Agregar destino')]", + "page": "studio" + }, + { + "id": "scenes.show_on_stage", + "description": "Botón 'Mostrar en el escenario' dentro del listado de escenas (thumbnail)", + "playwright": "text=Mostrar en el escenario", + "css": "button:has-text('Mostrar en el escenario')", + "xpath": "//button[contains(normalize-space(.), 'Mostrar en el escenario')]", + "page": "studio-aside-scenes" + }, + { + "id": "scenes.new_scene", + "description": "Botón 'Nueva escena' en panel de Scenes", + "playwright": "text=Nueva escena", + "css": "button:has-text('Nueva escena')", + "xpath": "//button[contains(normalize-space(.), 'Nueva escena')]", + "page": "studio-aside-scenes" + }, + { + "id": "assets.change_logo_section", + "description": "Control para cambiar la sección del logo en Assets", + "playwright": "text=Cambiar la sección del logo", + "css": "button:has-text('Cambiar la sección del logo')", + "xpath": "//button[contains(normalize-space(.), 'Cambiar la sección del logo')]", + "page": "studio-aside-assets" + }, + { + "id": "layouts.preset_individual", + "description": "Botón de preset diseño 'Individual' (uno de los presets listados)", + "playwright": "text=Diseño Individual", + "css": "button:has-text('Diseño Individual'), button:has-text('Individual Central')", + "xpath": "//button[contains(normalize-space(.), 'Diseño Individual') or contains(normalize-space(.),'Individual Central')]", + "page": "studio" + }, + { + "id": "studio.leave_link", + "description": "Link 'Salir del estudio' para cerrar la sesión del studio", + "playwright": "text=Salir del estudio", + "css": "a:has-text('Salir del estudio'), button:has-text('Salir del estudio')", + "xpath": "//a[contains(normalize-space(.), 'Salir del estudio')] | //button[contains(normalize-space(.), 'Salir del estudio')]", + "page": "studio" + } + ] +} diff --git a/packages/studio-panel/e2e/server.mjs b/packages/studio-panel/e2e/server.mjs new file mode 100644 index 0000000..ab0a333 --- /dev/null +++ b/packages/studio-panel/e2e/server.mjs @@ -0,0 +1,42 @@ +import http from 'http'; +import fs from 'fs'; +import path from 'path'; + +const port = process.env.PORT ? Number(process.env.PORT) : 5174; +const staticDir = path.resolve(process.cwd(), './static'); + +const mime = { + '.html': 'text/html', + '.js': 'application/javascript', + '.css': 'text/css', + '.json': 'application/json', + '.png': 'image/png', +}; + +const server = http.createServer((req, res) => { + try { + const reqPath = req.url === '/' ? '/sender.html' : req.url; + const filePath = path.join(staticDir, decodeURIComponent(reqPath)); + if (!filePath.startsWith(staticDir)) { + res.writeHead(403); res.end('Forbidden'); return; + } + if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { + const ext = path.extname(filePath); + res.writeHead(200, { 'Content-Type': mime[ext] || 'text/plain' }); + fs.createReadStream(filePath).pipe(res); + } else { + res.writeHead(404); res.end('Not found'); + } + } catch (e) { + res.writeHead(500); res.end('Server error'); + } +}); + +server.listen(port, () => { + console.log(`Static server running on http://localhost:${port}`); +}); + +// Graceful shutdown +process.on('SIGINT', () => server.close(() => process.exit(0))); +process.on('SIGTERM', () => server.close(() => process.exit(0))); + diff --git a/packages/studio-panel/e2e/simulated_flow.mjs b/packages/studio-panel/e2e/simulated_flow.mjs new file mode 100644 index 0000000..0ee57ed --- /dev/null +++ b/packages/studio-panel/e2e/simulated_flow.mjs @@ -0,0 +1,95 @@ +#!/usr/bin/env node +// Simulated E2E flow for Studio Panel +// - POST /api/session to token server +// - open studio receiver URL or studio page and assert token reception +// - save screenshots to /tmp + +import fs from 'fs'; +import fetch from 'node-fetch'; + +const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; +const STUDIO_BASE = process.env.STUDIO_URL || 'http://localhost:3020'; +const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 30000); + +function log(...args) { console.log(new Date().toISOString(), ...args); } + +async function createSession() { + log('Creating session at', TOKEN_SERVER); + const res = await fetch(`${TOKEN_SERVER}/api/session`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ room: 'e2e-room', username: 'sim-scripter' }) + }); + if (!res.ok) { + const t = await res.text(); + throw new Error(`Token server returned ${res.status}: ${t}`); + } + const body = await res.json(); + log('Session created:', body.id || '(no id)', 'studioUrl=', body.studioUrl); + return body; +} + +async function runPlaywright(url) { + log('Attempting Playwright flow for', url); + let playwright; + try { playwright = await import('playwright'); } catch (e) { log('Playwright not available:', e.message); return { available: false }; } + const { chromium } = playwright; + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + const resp = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: TIMEOUT }); + log('Page loaded status', resp && resp.status()); + // try to find #status text + try { + const status = page.locator('#status'); + await status.waitFor({ timeout: 5000 }); + const txt = await status.textContent(); + log('#status text:', txt && txt.slice(0,200)); + } catch (e) { + log('No #status element or timeout:', e.message); + } + const shot = `/tmp/e2e_playwright_${Date.now()}.png`; + await page.screenshot({ path: shot, fullPage: true }); + log('Saved screenshot', shot); + await browser.close(); + return { available: true, screenshot: shot }; +} + +async function fallbackHttp(url, sessionId, token) { + log('Fallback HTTP: GET', url); + try { + const r = await fetch(url); + log('GET status', r.status, 'content-type', r.headers.get('content-type')); + const txt = await r.text(); + const found = txt.includes('Token recibido') || txt.includes('LIVEKIT_TOKEN') || txt.includes(token); + log('Token present in body?', found); + const shotPath = `/tmp/e2e_http_${Date.now()}.html`; + fs.writeFileSync(shotPath, txt); + log('Saved page HTML to', shotPath); + return { ok: true, found, path: shotPath }; + } catch (e) { + log('HTTP fallback failed', e.message); + return { ok: false, error: e.message }; + } +} + +(async () => { + try { + const session = await createSession(); + const studioUrl = session.redirectUrl || session.studioUrl || (session.id ? `${STUDIO_BASE}/${session.id}` : null); + if (!studioUrl) throw new Error('No studio url returned by token server'); + + // Prefer Playwright flow + const pw = await runPlaywright(studioUrl); + if (pw.available) { log('Playwright flow done'); process.exit(0); } + + // fallback: HTTP check + const fb = await fallbackHttp(studioUrl, session.id, session.token || ''); + if (fb.ok) process.exit(0); + process.exit(2); + } catch (err) { + log('E2E error', err.message); + process.exit(1); + } +})(); + diff --git a/packages/studio-panel/e2e/static/sender.html b/packages/studio-panel/e2e/static/sender.html new file mode 100644 index 0000000..3284839 --- /dev/null +++ b/packages/studio-panel/e2e/static/sender.html @@ -0,0 +1,48 @@ + + + + + Sender (E2E) + + + + +

+  
+
+
diff --git a/packages/studio-panel/e2e/static/studio.html b/packages/studio-panel/e2e/static/studio.html
new file mode 100644
index 0000000..bf62e75
--- /dev/null
+++ b/packages/studio-panel/e2e/static/studio.html
@@ -0,0 +1,38 @@
+
+
+
+  
+  Studio (E2E)
+
+
+  
Esperando token...
+ + + diff --git a/packages/studio-panel/e2e/tests/postMessage.e2e.spec.js b/packages/studio-panel/e2e/tests/postMessage.e2e.spec.js new file mode 100644 index 0000000..15ab8ef --- /dev/null +++ b/packages/studio-panel/e2e/tests/postMessage.e2e.spec.js @@ -0,0 +1,51 @@ +const { test, expect } = require('@playwright/test'); +const { spawn } = require('child_process'); +const path = require('path'); + +const staticServerPath = path.resolve(__dirname, '..', 'server.mjs'); + +let serverProc; + +test.beforeAll(async () => { + // start static server + serverProc = spawn(process.execPath, [staticServerPath], { env: { ...process.env, PORT: '5174' }, stdio: 'inherit' }); + // wait a bit for server to start + await new Promise(resolve => setTimeout(resolve, 400)); +}); + +test.afterAll(async () => { + if (serverProc) { + serverProc.kill(); + } +}); + +test('handshake: sender -> studio via postMessage and ACKs', async ({ page, context }) => { + const base = 'http://localhost:5174'; + + // open sender page + await page.goto(base + '/sender.html'); + // open popup by clicking + await page.click('#open'); + // give popup time to open and be ready + await new Promise(r => setTimeout(r, 300)); + + // send token + await page.click('#send'); + + // wait for token ack from studio + await page.waitForFunction(() => { + const p = document.querySelector('pre'); + return p && p.textContent && p.textContent.includes('LIVEKIT_TOKEN_ACK'); + }, { timeout: 5000 }); + + // wait for connected ack + await page.waitForFunction(() => { + const p = document.querySelector('pre'); + return p && p.textContent && p.textContent.includes('LIVEKIT_ACK') && p.textContent.includes('connected'); + }, { timeout: 5000 }); + + const log = await page.$eval('pre', el => el.textContent); + expect(log).toContain('LIVEKIT_TOKEN_ACK'); + expect(log).toContain('LIVEKIT_ACK'); +}); + diff --git a/packages/studio-panel/index.html b/packages/studio-panel/index.html index 43bb313..6983c37 100644 --- a/packages/studio-panel/index.html +++ b/packages/studio-panel/index.html @@ -8,7 +8,43 @@
+ +
Esperando token...
+ - diff --git a/packages/studio-panel/package.json b/packages/studio-panel/package.json index 23aa40a..b02b133 100644 --- a/packages/studio-panel/package.json +++ b/packages/studio-panel/package.json @@ -6,34 +6,40 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview", + "preview": "vite preview --host", "test": "vitest", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "e2e": "node ./e2e/playwright_test.mjs" }, "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0", - "avanza-ui": "workspace:*", "@livekit/components-react": "^2.7.2", "@livekit/components-styles": "^1.1.5", - "livekit-client": "^2.8.2" + "avanza-ui": "file:../avanza-ui", + "livekit-client": "^2.8.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": { - "typescript": "^5.5.0", - "vite": "^5.0.0", - "@vitejs/plugin-react": "^4.0.0", - "vitest": "^1.1.8", - "@testing-library/react": "^14.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/user-event": "^14.4.3", - "@storybook/react": "^8.0.0", - "@storybook/react-vite": "^8.0.0", + "@playwright/test": "1.51.0", "@storybook/addon-essentials": "^8.0.0", "@storybook/addon-interactions": "^8.0.0", "@storybook/addon-links": "^8.0.0", "@storybook/blocks": "^8.0.0", - "storybook": "^8.0.0" + "@storybook/react": "^8.0.0", + "@storybook/react-vite": "^8.0.0", + "@tailwindcss/postcss": "^4.1.17", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", + "@vitejs/plugin-react": "^4.0.0", + "node-fetch": "^3.3.1", + "playwright": "^1.51.0", + "storybook": "^8.0.0", + "tailwindcss": "^4.1.17", + "typescript": "^5.5.0", + "vite": "^5.0.0", + "vitest": "^1.1.8" }, "vitest": { "test": { @@ -41,5 +47,12 @@ "setupFiles": "./src/setupTests.ts", "globals": true } - } + }, + "main": "index.js", + "directories": { + "test": "tests" + }, + "keywords": [], + "author": "", + "license": "ISC" } diff --git a/packages/studio-panel/playwright.config.ts b/packages/studio-panel/playwright.config.ts new file mode 100644 index 0000000..8d875ef --- /dev/null +++ b/packages/studio-panel/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: 'tests/e2e', + timeout: 60_000, + expect: { timeout: 5000 }, + fullyParallel: false, + reporter: [['list'], ['html', { outputFolder: 'playwright-report' }]], + use: { + headless: true, + viewport: { width: 1280, height: 720 }, + ignoreHTTPSErrors: true, + actionTimeout: 10000, + }, + projects: [ + { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, + ], +}); + diff --git a/packages/studio-panel/postcss.config.cjs b/packages/studio-panel/postcss.config.cjs index fdfd500..4155398 100644 --- a/packages/studio-panel/postcss.config.cjs +++ b/packages/studio-panel/postcss.config.cjs @@ -1,7 +1,5 @@ -module.exports = { - plugins: { - // use the PostCSS plugin package for Tailwind v4 - '@tailwindcss/postcss': {}, - autoprefixer: {}, - }, -} +// Minimal PostCSS config for studio-panel - disabled to avoid Tailwind/PostCSS plugin issues during development. +// If you want to enable Tailwind processing later, replace this file with a proper config +// that uses '@tailwindcss/postcss' or 'tailwindcss' and avoid top-level requires that may throw. + +module.exports = {}; diff --git a/packages/studio-panel/public/debug-styles.html b/packages/studio-panel/public/debug-styles.html new file mode 100644 index 0000000..23affd4 --- /dev/null +++ b/packages/studio-panel/public/debug-styles.html @@ -0,0 +1,79 @@ + + + + + + Debug Styles - Studio Panel + + + +

Debug: document.styleSheets

+
Cargando...
+
+ + + diff --git a/packages/studio-panel/public/simulate_postmessage.html b/packages/studio-panel/public/simulate_postmessage.html new file mode 100644 index 0000000..0f5b740 --- /dev/null +++ b/packages/studio-panel/public/simulate_postmessage.html @@ -0,0 +1,154 @@ + + + + + + Broadcast to Studio - Simulate (with token fetch) + + + +

Broadcast Simulator (token fetch)

+

Simula broadcast-panel: solicita token al backend y se lo envía por postMessage a la ventana del estudio.

+ + +

+ +

+ + + +
+ + +
+ +
+
Idle
+ + + + diff --git a/packages/studio-panel/public/studio_receiver.html b/packages/studio-panel/public/studio_receiver.html new file mode 100644 index 0000000..2ec7bf1 --- /dev/null +++ b/packages/studio-panel/public/studio_receiver.html @@ -0,0 +1,70 @@ + + + + + + Studio Receiver (Test) + + + +

Studio Receiver - listens for LIVEKIT_TOKEN

+
Esperando token...
+ + + diff --git a/packages/studio-panel/run_e2e_session.sh b/packages/studio-panel/run_e2e_session.sh new file mode 100755 index 0000000..c6a21b0 --- /dev/null +++ b/packages/studio-panel/run_e2e_session.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +# install deps (fast fail if missing) +npm ci --no-audit --no-fund +npx playwright install --with-deps || true + +# start a simple static server to serve public/ on port 3020 +PORT=3020 +PUBLIC_DIR="$ROOT/public" + +# prefer serve if available, else use npx http-server +if command -v serve > /dev/null 2>&1; then + serve -s "$PUBLIC_DIR" -l $PORT > /tmp/studio_static_server.log 2>&1 & + SERVER_PID=$! +else + npx http-server "$PUBLIC_DIR" -p $PORT > /tmp/studio_static_server.log 2>&1 & + SERVER_PID=$! +fi + +echo "Started static server (pid=$SERVER_PID), log: /tmp/studio_static_server.log" +sleep 1 + +# export envs for the test +export TOKEN_SERVER_URL=${TOKEN_SERVER_URL:-http://localhost:4000} +export STUDIO_URL=${STUDIO_URL:-http://localhost:3020} + +# run playwright test +npx playwright test tests/e2e/session_flow.spec.ts --project=chromium --config=playwright.config.ts || true + +# cleanup +if [ -n "${SERVER_PID:-}" ]; then + kill "$SERVER_PID" 2>/dev/null || true +fi + +echo "Artifacts (screenshots) in /tmp/e2e_*.png" +ls -la /tmp/e2e_*.png || true + +exit 0 diff --git a/packages/studio-panel/run_playwright_test.sh b/packages/studio-panel/run_playwright_test.sh new file mode 100755 index 0000000..f4d14d4 --- /dev/null +++ b/packages/studio-panel/run_playwright_test.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "$0")" && pwd) +cd "$ROOT_DIR" + +LOG=/tmp/playwright_debug.log +OUT=/tmp/playwright_run_output.log +SIMSHOT=/tmp/sim_postmessage_simulator.png +STUDIOSHOT=/tmp/sim_postmessage_studio.png + +echo "Running Playwright E2E test for studio-panel" +echo "Logs: $LOG Output: $OUT" + +# Ensure node modules exist +if [ ! -d node_modules/playwright ]; then + echo "Playwright not found in node_modules — installing as devDependency (this may modify package-lock) +" + npm install --no-audit --no-fund --no-save playwright +fi + +echo "Installing Playwright browsers (may require sudo on some systems)..." +npx playwright install --with-deps || true + +echo "Running test script... (this may take ~15s)" +# run and capture output +node --experimental-vm-modules scripts/playwright_postmessage_test.mjs > "$OUT" 2>&1 || true + +# Show summary +echo "\n=== Playwright run finished ===\n" +if [ -f "$LOG" ]; then + echo "Last 200 lines of $LOG:\n" + tail -n 200 "$LOG" +else + echo "$LOG not found" +fi + +if [ -f "$OUT" ]; then + echo "\nLast 200 lines of run output ($OUT):\n" + tail -n 200 "$OUT" +else + echo "$OUT not found" +fi + +if [ -f "$SIMSHOT" ]; then + echo "Simulator screenshot: $SIMSHOT" +else + echo "Simulator screenshot not found" +fi +if [ -f "$STUDIOSHOT" ]; then + echo "Studio screenshot: $STUDIOSHOT" +else + echo "Studio screenshot not found" +fi + +echo "\nIf the test failed, please paste the contents of the two log files above and attach the screenshots listed. +You can upload screenshots to an image host and paste URLs, or paste the relevant log sections here." + diff --git a/packages/studio-panel/scripts/check_styles_playwright.mjs b/packages/studio-panel/scripts/check_styles_playwright.mjs new file mode 100644 index 0000000..01b6e75 --- /dev/null +++ b/packages/studio-panel/scripts/check_styles_playwright.mjs @@ -0,0 +1,28 @@ +let playwright +try { + playwright = await import('playwright') +} catch (e) { + console.error('\nPlaywright no está instalado en este entorno.'); + console.error('Instálalo con: npm install -D playwright (en la raíz del repo) y luego ejecuta: npx playwright install'); + process.exitCode = 2 + throw e +} + +const { chromium } = playwright; + +(async () => { + const browser = await chromium.launch(); + const page = await browser.newPage(); + try { + // Target studio-panel dev server by default + await page.goto('http://localhost:3020/', { waitUntil: 'networkidle' , timeout: 10000}); + const sheets = await page.evaluate(() => Array.from(document.styleSheets).map(s => s.href || s.ownerNode?.textContent?.slice(0,50) || null)); + console.log('document.styleSheets count =', sheets.length); + console.log(JSON.stringify(sheets, null, 2)); + } catch (e) { + console.error('Error:', e.toString()); + process.exitCode = 2; + } finally { + await browser.close(); + } +})(); diff --git a/packages/studio-panel/scripts/check_styles_playwright_3021.mjs b/packages/studio-panel/scripts/check_styles_playwright_3021.mjs new file mode 100644 index 0000000..01c5f9e --- /dev/null +++ b/packages/studio-panel/scripts/check_styles_playwright_3021.mjs @@ -0,0 +1,29 @@ +let playwright +try { + playwright = await import('playwright') +} catch (e) { + console.error('\nPlaywright no está instalado en este entorno.'); + console.error('Instálalo con: npm install -D playwright (en la raíz del repo) y luego ejecuta: npx playwright install'); + process.exitCode = 2 + throw e +} + +const { chromium } = playwright; + +(async () => { + const browser = await chromium.launch({ headless: true }); + const page = await browser.newPage(); + try { + // Target studio-panel dev server on port 3021 + await page.goto('http://localhost:3021/', { waitUntil: 'networkidle' , timeout: 15000}); + const sheets = await page.evaluate(() => Array.from(document.styleSheets).map(s => s.href || s.ownerNode?.textContent?.slice(0,250) || null)); + console.log('document.styleSheets count =', sheets.length); + console.log(JSON.stringify(sheets, null, 2)); + } catch (e) { + console.error('Error:', e.toString()); + process.exitCode = 2; + } finally { + await browser.close(); + } +})(); + diff --git a/packages/studio-panel/scripts/e2e_portal_interaction.mjs b/packages/studio-panel/scripts/e2e_portal_interaction.mjs new file mode 100644 index 0000000..5266931 --- /dev/null +++ b/packages/studio-panel/scripts/e2e_portal_interaction.mjs @@ -0,0 +1,31 @@ +import { chromium } from 'playwright'; + +const WS = process.env.PLAYWRIGHT_WS_ENDPOINT || 'ws://192.168.1.20:3003'; +const REDIR = process.env.REDIR_URL; + +(async ()=>{ + if (!REDIR) { + console.error('REDIR_URL not provided'); + process.exit(2); + } + const browser = await chromium.connect({ wsEndpoint: WS }); + const context = await browser.newContext(); + const page = await context.newPage(); + page.on('console', m => console.log('PAGE:', m.text())); + try { + await page.goto(REDIR, { waitUntil: 'networkidle', timeout: 30000 }); + await page.waitForSelector('.studio-portal .layout-btn', { timeout: 5000 }).catch(()=>{}); + // click second layout + await page.evaluate(()=>{ const btns = document.querySelectorAll('.layout-btn'); if (btns && btns[1]) (btns[1] as HTMLElement).click(); }); + await page.waitForFunction(()=> !!document.querySelector('.studio-room')?.getAttribute('data-layout'), { timeout: 3000 }).catch(()=>{}); + await page.evaluate(()=>{ const rec = document.querySelector('.btn-record') as HTMLElement; if(rec) rec.click(); }); + await page.waitForTimeout(1500); + await page.screenshot({ path: '/tmp/e2e_portal_interaction.png', fullPage:true}); + console.log('PAGE URL', page.url()); + } catch (err) { + console.error('E2E error', err); + } finally { + await browser.close(); + } +})(); + diff --git a/packages/studio-panel/scripts/e2e_session_http_runner.mjs b/packages/studio-panel/scripts/e2e_session_http_runner.mjs new file mode 100644 index 0000000..35baeb2 --- /dev/null +++ b/packages/studio-panel/scripts/e2e_session_http_runner.mjs @@ -0,0 +1,59 @@ +import fetch from 'node-fetch'; +import fs from 'fs'; + +const LOG = '/tmp/e2e_http_runner.log'; +function writeLog(...args){ try{ fs.appendFileSync(LOG, args.map(a=>typeof a==='string'?a:JSON.stringify(a)).join(' ')+'\n') }catch(e){} + console.log(...args); +} + +const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; +const STUDIO_URL = process.env.STUDIO_URL || 'http://localhost:3020'; +const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 15000); + +(async ()=>{ + try{ + writeLog('START HTTP runner', new Date().toISOString(), 'TOKEN_SERVER='+TOKEN_SERVER); + + // 1) create session + const resp = await fetch(`${TOKEN_SERVER}/api/session`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ room: 'http-e2e-room', username: 'http-runner' }) + }); + writeLog('POST /api/session status', resp.status); + const json = await resp.json(); + writeLog('POST response', json); + + const redirectUrl = json.redirectUrl || json.studioUrl || null; + if (!redirectUrl){ writeLog('No redirectUrl in response, abort'); process.exit(2); } + + writeLog('Redirect URL:', redirectUrl); + + // 2) GET redirect URL + const r2 = await fetch(redirectUrl, { method: 'GET' }); + writeLog('GET redirect status', r2.status, 'content-type', r2.headers.get('content-type')); + const bodyText = await r2.text(); + writeLog('GET redirect body length', bodyText.length); + + // 3) checks + const hasTokenInUrl = /token=/.test(redirectUrl); + const hasTokenInBody = /token=/.test(bodyText) || /Token recibido/.test(bodyText) || /LIVEKIT_ACK/.test(bodyText); + writeLog('hasTokenInUrl', hasTokenInUrl, 'hasTokenInBody', hasTokenInBody); + + // 4) session lookup if id present + if (json.id){ + try{ + const s = await fetch(`${TOKEN_SERVER}/api/session/${json.id}`); + writeLog('/api/session/:id status', s.status); + const sjson = await s.json(); writeLog('session lookup', sjson); + }catch(e){ writeLog('session lookup error', String(e)); } + } + + // save an excerpt of body to file + const out = '/tmp/e2e_http_runner_body.html'; + try{ fs.writeFileSync(out, bodyText.slice(0, 20000)); writeLog('Saved redirect HTML excerpt to', out); }catch(e){ writeLog('Failed writing excerpt', String(e)); } + + writeLog('FINISH OK'); + process.exit(0); + }catch(err){ writeLog('Runner error', String(err)); process.exit(1); } +})(); + diff --git a/packages/studio-panel/scripts/e2e_session_runner.mjs b/packages/studio-panel/scripts/e2e_session_runner.mjs new file mode 100644 index 0000000..07fbb22 --- /dev/null +++ b/packages/studio-panel/scripts/e2e_session_runner.mjs @@ -0,0 +1,103 @@ +import fetch from 'node-fetch'; +import fs from 'fs'; + +const LOG_PATH = '/tmp/e2e_node_runner.log'; +function log(...args) { try { fs.appendFileSync(LOG_PATH, args.map(a=>typeof a==='string'?a:JSON.stringify(a)).join(' ') + '\n') }catch(e){} + console.log(...args) +} + +let playwrightAvailable = true; +let playwright = null; +try { + // dynamic import to allow fallback if playwright not installed + playwright = await import('playwright'); +} catch (err) { + playwrightAvailable = false; + log('Playwright not available, will fallback to HTTP checks:', String(err)); +} + +const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'http://localhost:4000'; +const TIMEOUT = Number(process.env.E2E_TIMEOUT_MS || 30000); + +(async () => { + try { + log('Creating session at token server:', TOKEN_SERVER); + const res = await fetch(`${TOKEN_SERVER}/api/session`, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ room: 'e2e-room', username: 'node-runner' }) + }); + if (!res.ok) { + log('Token server returned', res.status); + log(await res.text()); + process.exitCode = 2; return; + } + const body = await res.json(); + log('Session created:', body); + const url = body.redirectUrl || body.studioUrl || (body.id ? `${(process.env.STUDIO_URL||'http://localhost:3020')}/studio_receiver.html?token=${encodeURIComponent(body.token||'')}` : null); + if (!url) { log('No redirectUrl'); process.exitCode = 3; return } + + // If playwright available, open browser and verify #status text + if (playwrightAvailable && playwright) { + log('Launching Playwright chromium'); + const { chromium } = playwright; + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + log('Opening studio page:', url); + const resp = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: TIMEOUT }); + log('Loaded page status:', resp && resp.status()); + + const status = page.locator('#status'); + try { + await status.waitFor({ timeout: TIMEOUT }); + const text = await status.textContent(); + log('Status text:', (text||'').slice(0,400)); + if ((text || '').includes('Token recibido')) { + log('Studio received token OK'); + } else { + log('Studio status did not include expected text'); + } + } catch (err) { + log('Timeout waiting for #status', String(err)); + } + + const shot1 = '/tmp/e2e_studio_runner.png'; + await page.screenshot({ path: shot1, fullPage: true }); + log('Screenshot saved:', shot1); + + await browser.close(); + process.exitCode = 0; + return; + } + + // Fallback: simple HTTP checks + log('Playwright not available: performing HTTP-only checks for', url); + try { + const r = await fetch(url, { method: 'GET' }); + log('GET redirectUrl status', r.status, 'content-type', r.headers.get('content-type')); + const text = await r.text(); + // look for token in body or in url + const hasTokenInBody = /token=/.test(text) || /Token recibido/.test(text) || /LIVEKIT_ACK/.test(text); + const hasTokenInUrl = /token=/.test(url); + log('hasTokenInBody', hasTokenInBody, 'hasTokenInUrl', hasTokenInUrl); + } catch (err) { + log('Error fetching redirectUrl:', String(err)); + } + + // Also check session retrieval via API + if (body.id) { + try { + const s = await fetch(`${TOKEN_SERVER}/api/session/${body.id}`); + log('/api/session/:id status', s.status); + if (s.ok) { + const js = await s.json(); log('session lookup:', js); + } else log('session lookup failed'); + } catch (err) { log('session lookup error', String(err)) } + } + + process.exitCode = 0; + } catch (err) { + log('E2E runner error', String(err)); + process.exitCode = 1; + } +})(); diff --git a/packages/studio-panel/scripts/e2e_simulate_guests.mjs b/packages/studio-panel/scripts/e2e_simulate_guests.mjs new file mode 100644 index 0000000..81b311f --- /dev/null +++ b/packages/studio-panel/scripts/e2e_simulate_guests.mjs @@ -0,0 +1,164 @@ +import { chromium } from 'playwright'; +import fs from 'fs'; + +const BACKEND = process.env.BACKEND_URL || 'http://127.0.0.1:4000'; +const GUESTS = Number(process.env.GUESTS || '2'); +const HEADLESS = process.env.HEADLESS !== 'false'; +const VERBOSE_LOG = '/tmp/e2e_sim_verbose.log'; + +function vlog(...args){ + const line = `[${new Date().toISOString()}] ` + args.map(a => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '); + try { fs.appendFileSync(VERBOSE_LOG, line + '\n'); } catch(e){} + console.log(line); +} + +async function createSession(username) { + vlog('createSession ->', username); + try { + const res = await fetch(`${BACKEND}/api/session`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ room: 'studio-demo', username }), + // keepAlive not available in fetch, but backend should be reachable + }); + if (!res.ok) { + const txt = await res.text().catch(()=>''); + throw new Error(`session create failed ${res.status} ${txt}`); + } + const j = await res.json(); + vlog('session created', j.redirectUrl || j); + return j; + } catch (e) { + vlog('createSession error', String(e)); + throw e; + } +} + +async function checkBackend(){ + try { + vlog('Checking backend health at', BACKEND + '/health'); + const r = await fetch(`${BACKEND}/health`, { method: 'GET', cache: 'no-store' , redirect: 'follow' }); + if (!r.ok) { vlog('backend health not ok', r.status); return false; } + const j = await r.json().catch(()=>null); + vlog('backend health response', j || ''); + return true; + } catch (e) { vlog('backend health check failed', String(e)); return false; } +} + +(async ()=>{ + try{ + // reset verbose log + try{ fs.writeFileSync(VERBOSE_LOG, ''); } catch(e){} + vlog('E2E simulate guests - starting', { BACKEND, GUESTS, HEADLESS }); + + const ok = await checkBackend(); + if (!ok) { + vlog('Backend not available at', BACKEND, ' -> aborting'); + process.exit(2); + } + + // create sessions + const sessions = []; + try { + const mod = await createSession('moderator-e2e'); + sessions.push({ role: 'moderator', ...mod }); + for (let i=0;is.role==='moderator'); + if (!modSession) throw new Error('no moderator session'); + const modContext = await browser.newContext({ permissions: ['camera','microphone'] }); + const modPage = await modContext.newPage(); + modPage.on('console', m => vlog('MOD PAGE:', m.text())); + vlog('Opening moderator at', modSession.redirectUrl); + await modPage.goto(modSession.redirectUrl, { waitUntil: 'networkidle', timeout: 60000 }); + contexts.push(modContext); pages.push(modPage); + + // open guests + for (let s of sessions.filter(x=>x.role==='guest')){ + const ctx = await browser.newContext({ permissions: ['camera','microphone'] }); + const pg = await ctx.newPage(); + pg.on('console', m => vlog('GUEST PAGE:', m.text())); + vlog('Opening guest at', s.redirectUrl); + await pg.goto(s.redirectUrl, { waitUntil: 'networkidle', timeout: 60000 }); + contexts.push(ctx); pages.push(pg); + } + + // wait short + await modPage.waitForTimeout(2000); + + // click Conectar todos on moderator + vlog('Clicking Conectar todos'); + await modPage.evaluate(()=>{ + const btn = Array.from(document.querySelectorAll('button')).find(b => { + const txt = (b.textContent||'').trim().toLowerCase(); + return txt.includes('conectar todos') || txt.includes('connect all'); + }); + if (btn && typeof btn.click === 'function') btn.click(); + }); + + // wait for invites to be processed; wait until an svg line has green stroke + vlog('Waiting for accepted lines...'); + const accepted = await modPage.waitForFunction(()=>{ + const svg = document.querySelector('.connections-overlay'); + if (!svg) return false; + const lines = Array.from(svg.querySelectorAll('line')); + return lines.some(l => ((l.getAttribute('stroke')||'').toLowerCase() === '#34d399')); + }, { timeout: 20000 }).catch(()=>null); + + if (accepted) vlog('Accepted detected'); else vlog('No accepted detected within timeout'); + + // screenshots + const outDir = 'packages/studio-panel/.playwright-mcp'; + try{ fs.mkdirSync(outDir, { recursive: true }); } catch(e){} + const modShot = '/tmp/e2e_sim_moderator.png'; + await modPage.screenshot({ path: modShot, fullPage:true }); + fs.copyFileSync(modShot, `${outDir}/${modShot.split('/').pop()}`); + vlog('Saved moderator screenshot to', modShot); + + for (let i=0;i{ + log('Starting playwright_mcp_flow'); + // Connect to remote server if reachable; else fall back to local launch + let browser; + try { + if (PLAYWRIGHT_WS) { + log('Attempting to connect to remote Playwright WS at ' + PLAYWRIGHT_WS); + try { + browser = await chromium.connect({ wsEndpoint: PLAYWRIGHT_WS, timeout: 10000 }); + remoteBrowser = browser; + log('Connected to remote Playwright browser via WS'); + } catch (err) { + // If server responded with 428 (version mismatch) surface clear message + const emsg = (err && err.message) ? String(err.message) : String(err); + if (emsg.includes('428') || emsg.toLowerCase().includes('version')) { + log('Failed to connect to remote Playwright WS due to version mismatch: ' + emsg); + log('ACTION REQUIRED: Sync Playwright versions. Server reports a different Playwright version than the client.'); + } else { + log('Failed to connect to remote Playwright WS: ' + err + '. Falling back to local launch.'); + } + } + } + } catch (e) { log('Remote connect error: '+e); } + + if (!browser) { + log('Launching local chromium'); + launchedBrowser = await chromium.launch({ headless: true, args: ['--no-sandbox','--disable-dev-shm-usage'] }); + browser = launchedBrowser; + } + const context = await browser.newContext(); + const page = await context.newPage(); + page.on('console', m => log('PAGE LOG: ' + m.text())); + + // Load selectors JSON + // convert module URL to file path correctly + const selPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../e2e/selectors_streamyard.json'); + let SELECTORS = {}; + try{ + const raw = fs.readFileSync(selPath, 'utf8'); + const parsed = JSON.parse(raw); + (parsed.selectors || []).forEach(s => { SELECTORS[s.id] = s; }); + log(`Loaded ${Object.keys(SELECTORS).length} selectors from ${selPath}`); + }catch(err){ log('Failed to load selectors JSON: '+err); } + + function getSel(id){ + const s = SELECTORS[id]; + if (!s) return null; + // prefer Playwright selector string if present + return s.playwright || s.css || s.xpath || null; + } + + // Configurable env vars + const BROADCAST_URL = process.env.BROADCAST_URL || process.env.BROADCAST_LIST_URL || 'https://streamyard.com/broadcasts'; + const BROADCAST_TIMEOUT = Number(process.env.BROADCAST_TIMEOUT_MS || 30000); + const STUDIO_TIMEOUT = Number(process.env.STUDIO_TIMEOUT_MS || 30000); + + try{ + log('Navigating to broadcast list: ' + BROADCAST_URL); + await page.goto(BROADCAST_URL, { waitUntil: 'networkidle', timeout: BROADCAST_TIMEOUT }); + log('Broadcast page loaded: ' + page.url()); + + // If the broadcast page attempted to fetch a token but failed due to CORS, detect it in console logs + // We'll check page content for common CORS error markers and fallback to backend-api session creation. + const pageContent = await page.content().catch(()=>null); + const corsIssue = pageContent && (pageContent.includes('Failed to fetch') || pageContent.includes('blocked by CORS') || pageContent.includes('error%3A%20TypeError')); + if (corsIssue) { + log('Detected token fetch CORS issue on broadcast page — will create session via BACKEND_API_URL fallback'); + // First attempt: try to fetch token directly from token server (server-side request) + const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || process.env.VITE_TOKEN_SERVER_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host'; + try { + log('Attempting direct token request to token-server: ' + TOKEN_SERVER + '/api/token'); + const room = process.env.TEST_ROOM || 'studio-demo'; + const username = process.env.TEST_USERNAME || 'simulator'; + const tokenResp = await context.request.get(TOKEN_SERVER + `/api/token?room=${encodeURIComponent(room)}&username=${encodeURIComponent(username)}`); + if (tokenResp && tokenResp.ok()) { + const json = await tokenResp.json(); + log('Token server returned JSON: ' + JSON.stringify(Object.keys(json))); + const token = json.token || json?.token; + const serverUrl = json.url || json?.url || process.env.VITE_LIVEKIT_WS_URL || process.env.VITE_LIVEKIT_URL; + if (token) { + // compose studio URL + const studioBase = (process.env.VITE_STUDIO_URL || 'http://localhost:3020').replace(/\/$/, ''); + const redirectUrl = `${studioBase}/studio_receiver.html?token=${encodeURIComponent(token)}&room=${encodeURIComponent(room)}&username=${encodeURIComponent(username)}&serverUrl=${encodeURIComponent(serverUrl||'')}`; + log('Opening studio directly with token from token-server: ' + redirectUrl); + const studioPage = await context.newPage(); + await studioPage.goto(redirectUrl, { waitUntil: 'networkidle', timeout: 30000 }).catch(e=>log('studio goto failed: '+e)); + page = studioPage; // eslint-disable-line + // skip backend fallback + corsIssue = false; + } else { + log('Token server response did not include token'); + } + } else { + log('Token server request failed, status=' + (tokenResp && tokenResp.status())); + } + } catch (e) { + log('Direct token-server request failed: ' + e); + } + + const BACKEND_API = process.env.BACKEND_API_URL || 'http://localhost:4000'; + try { + log('Creating session via backend API: ' + BACKEND_API + '/api/session'); + // use Playwright's request to perform POST (works with remote browser) + const room = process.env.TEST_ROOM || 'studio-demo'; + const username = process.env.TEST_USERNAME || 'simulator'; + const ttl = Number(process.env.TEST_TTL || 300); + const resp = await context.request.post(BACKEND_API + '/api/session', { + data: { room, username, ttl } + }); + if (resp && resp.status() === 200) { + const json = await resp.json(); + log('Session created: ' + JSON.stringify(json)); + const redirectUrl = json.redirectUrl || json.studioUrl; + if (redirectUrl) { + log('Opening studio redirectUrl from backend session: ' + redirectUrl); + // open new page for studio + const studioPage = await context.newPage(); + await studioPage.goto(redirectUrl, { waitUntil: 'networkidle', timeout: 30000 }).catch(e=>log('studio goto failed: '+e)); + // replace studioPage variable used below + page = studioPage; // eslint-disable-line + } else { + log('Backend session response did not include redirectUrl/studioUrl'); + } + } else { + log('Backend session creation failed, status=' + (resp && resp.status())); + } + } catch (e) { + log('Error creating session via backend API fallback: ' + e); + } + } + + // --- Login handling: if redirected to /login or login form present, attempt automated login using env vars + try { + const maybeLogin = page.url().includes('/login'); + // also detect common login form inputs + const hasEmailInput = await page.locator('input[type="email"], input[name="email"], input[id*=email]').count(); + const hasPasswordInput = await page.locator('input[type="password"], input[name="password"], input[id*=password]').count(); + if (maybeLogin || hasEmailInput || hasPasswordInput) { + const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL || process.env.STREAMYARD_TEST_EMAIL || ''; + const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD || process.env.STREAMYARD_TEST_PASSWORD || ''; + log('Detected login page/form; env email present? ' + (TEST_USER_EMAIL ? 'yes' : 'no')); + if (TEST_USER_EMAIL && TEST_USER_PASSWORD) { + // fill email + const emailSelectors = ['input[type="email"]','input[name="email"]','input[id*=email]']; + for (const sel of emailSelectors) { + try { if (await page.locator(sel).count()) { await page.fill(sel, TEST_USER_EMAIL); log('Filled email using selector: '+sel); break; } } catch(e){} + } + // fill password + const passSelectors = ['input[type="password"]','input[name="password"]','input[id*=password]']; + for (const sel of passSelectors) { + try { if (await page.locator(sel).count()) { await page.fill(sel, TEST_USER_PASSWORD); log('Filled password using selector: '+sel); break; } } catch(e){} + } + // try submit with several button selectors + const submitSelectors = [ + 'button:has-text("Iniciar sesión")', + 'button:has-text("Iniciar Sesión")', + 'button:has-text("Sign in")', + 'button[type="submit"]' + ]; + let clicked = false; + for (const s of submitSelectors) { + try { + if (await page.locator(s).count()) { await page.click(s); log('Clicked submit using selector: '+s); clicked = true; break; } + } catch(e){} + } + // if no button clicked, try pressing Enter on password field + if (!clicked) { + try { await page.keyboard.press('Enter'); log('Pressed Enter to submit login form'); } catch(e){} + } + // wait for navigation away from /login or for broadcasts path + try { + await page.waitForFunction(() => !location.pathname.includes('/login'), { timeout: 20000 }); + log('Login appears to have completed; current URL: ' + page.url()); + // small delay to allow app to settle + await page.waitForLoadState('networkidle'); + } catch(e) { log('Login did not navigate away within timeout, continuing anyway: '+e); } + } else { + log('No TEST_USER_EMAIL/TEST_USER_PASSWORD provided in env; cannot auto-login.'); + } + } + } catch (e) { log('Login detection/attempt failed: '+e); } + + // Click the Enter Studio link (first match) + const enterSel = getSel('broadcasts.enter_studio_link'); + if (!enterSel) throw new Error('Selector broadcasts.enter_studio_link not found'); + try{ + log('Waiting for enter studio link: ' + enterSel); + const enterLocator = page.locator(enterSel).first(); + await enterLocator.waitFor({ timeout: 10000 }); + await enterLocator.click({ force: true }); + log('Clicked enter studio link'); + } catch(e){ log('Failed clicking enter studio link: '+e); } + + // Wait for navigation to prejoin/studio + await page.waitForLoadState('networkidle'); + log('After click current URL: ' + page.url()); + + // If prejoin appears in same page, interact; else try to find new page in context + let studioPage = page; + + // Try start camera + const startCameraSel = getSel('prejoin.start_camera_button'); + const joinWithoutSel = getSel('prejoin.join_without_devices'); + const enterStudioBtnSel = getSel('prejoin.enter_studio_button'); + + // If start camera exists, try click + if (startCameraSel) { + try{ + const loc = studioPage.locator(startCameraSel).first(); + await loc.waitFor({ timeout: 6000 }); + await loc.click({ force:true }); + log('Clicked start camera'); + }catch(e){ log('start camera not available or failed: '+e); + // try fallback + if (joinWithoutSel){ try{ const j = studioPage.locator(joinWithoutSel).first(); await j.waitFor({ timeout:2000 }); await j.click({ force:true }); log('Clicked join without devices fallback'); }catch(err){ log('join without devices not found: '+err); } } + } + } else if (joinWithoutSel) { + try{ const j = studioPage.locator(joinWithoutSel).first(); await j.waitFor({ timeout:2000 }); await j.click({ force:true }); log('Clicked join without devices fallback (no startCamera selector)'); }catch(err){ log('join without devices not found (no startCamera selector): '+err); } + } + + // Click final Enter if exists + if (enterStudioBtnSel){ try{ const ebtn = studioPage.locator(enterStudioBtnSel).first(); await ebtn.waitFor({ timeout:5000 }); await ebtn.click({ force:true }); log('Clicked final enter studio button'); }catch(e){ log('no final enter button: '+e); } } + + // Wait for studio to be ready: look for studio.record_button or studio.add_guest_button + const studioReadySel = getSel('studio.record_button') || getSel('studio.add_guest_button'); + if (studioReadySel){ + log('Waiting for studio ready selector: ' + studioReadySel); + try{ + await studioPage.waitForSelector(studioReadySel, { timeout: STUDIO_TIMEOUT }); + log('Studio ready detected on page: ' + studioReadySel + ' url=' + studioPage.url()); + }catch(e){ + // maybe the app opened in a new tab - check other pages + log('Studio ready selector not found in current page, checking other context pages'); + const pages = context.pages(); + let found = false; + for (const p of pages){ + try{ + const u = p.url(); + const loc = p.locator(studioReadySel).first(); + if (await loc.count() > 0){ + log('Found studio ready selector in page: ' + u); + studioPage = p; + found = true; + break; + } + }catch(err){} + } + if (!found) log('Studio ready not found in any page'); + } + } + + // Capture screenshots + const simShot = '/tmp/playwright_mcp_broadcast.png'; + const studioShot = '/tmp/playwright_mcp_studio.png'; + try{ await page.screenshot({ path: simShot, fullPage: true }); log('Saved broadcast screenshot: ' + simShot); }catch(e){ log('Failed saving broadcast screenshot: '+e); } + try{ await studioPage.screenshot({ path: studioShot, fullPage: true }); log('Saved studio screenshot: ' + studioShot); }catch(e){ log('Failed saving studio screenshot: '+e); } + + log('Flow finished successfully (or attempted)'); + }catch(err){ log('Unhandled error in flow: ' + (err && err.stack ? err.stack : String(err))); } + finally{ + try{ await browser.close(); log('Browser closed'); }catch(e){ log('Error closing browser: '+e); } + log('Script finished'); + } +})(); diff --git a/packages/studio-panel/scripts/playwright_postmessage_test.mjs b/packages/studio-panel/scripts/playwright_postmessage_test.mjs new file mode 100644 index 0000000..4a977db --- /dev/null +++ b/packages/studio-panel/scripts/playwright_postmessage_test.mjs @@ -0,0 +1,152 @@ +import fs from 'fs'; +let playwright; +try { playwright = await import('playwright'); } catch (e) { fs.appendFileSync('/tmp/playwright_debug.log', `Playwright import error: ${e}\n`); process.exit(2); } +const { chromium } = playwright; + +const LOG = '/tmp/playwright_debug.log'; +function log(msg){ + const line = `[${new Date().toISOString()}] ${msg}\n`; + try{ fs.appendFileSync(LOG, line); } catch(e) {} +} + +(async ()=>{ + log('Starting playwright_postmessage_test'); + let browser; + try{ + browser = await chromium.launch({ headless: true, args: ['--no-sandbox','--disable-dev-shm-usage'] }); + log('Chromium launched'); + const context = await browser.newContext(); + const page = await context.newPage(); + page.on('console', m => log('PAGE LOG: ' + m.text())); + let studioConsoleLogs = []; + + // Use environment variables if provided, otherwise default to production domains + const BROADCAST_URL = process.env.BROADCAST_URL || 'https://avanzacast-broadcastpanel.bfzqqk.easypanel.host/post_token_to_studio.html?auto=1'; + const STUDIO_ORIGIN = process.env.STUDIO_ORIGIN || 'https://avanzacast-studio.bfzqqk.easypanel.host'; + + log('Navigating to broadcast URL: ' + BROADCAST_URL); + await page.goto(BROADCAST_URL, { waitUntil: 'networkidle', timeout: 30000 }); + log('Broadcast page loaded'); + + // Wait briefly for auto-run, otherwise click the open button if present + try{ + // if the page has a button with id 'run' or 'openSend', try to click it as fallback + const runBtn = await page.$('#run') || await page.$('#openSend'); + if (runBtn) { + log('Found run/open button on page; clicking to trigger flow'); + await runBtn.click(); + } + } catch(e){ log('No run button click fallback: ' + e); } + + // Wait up to 12s for the redirect to the studio (the broadcast page may open a popup or redirect) + log('Waiting for a new page whose origin matches ' + STUDIO_ORIGIN + ' (timeout 12s)'); + let studioPage = null; + const start = Date.now(); + const timeoutMs = 12000; + while (!studioPage && (Date.now() - start) < timeoutMs){ + const pages = context.pages(); + for (const p of pages){ + try{ + const u = p.url(); + if (u && u.startsWith(STUDIO_ORIGIN)) { studioPage = p; break; } + }catch(e){} + } + if (studioPage) break; + await new Promise(r=>setTimeout(r, 300)); + } + + if (!studioPage){ + log('Studio page not opened automatically; attempting to open studio receiver directly at ' + STUDIO_ORIGIN + '/studio_receiver.html'); + // open the studio receiver in the same context + studioPage = await context.newPage(); + await studioPage.goto(STUDIO_ORIGIN + '/studio_receiver.html', { waitUntil: 'networkidle', timeout: 30000 }).catch(e=>{ log('Goto studio_receiver failed: '+e); }); + } + + if (!studioPage) { + log('ERROR: Could not open studio page'); + } else { + // capture console logs from studio page to detect connected/ACK messages + studioPage.on('console', m => { + try { const txt = m.text(); studioConsoleLogs.push(txt); log('STUDIO PAGE LOG: ' + txt); } catch(e) {} + }); + log('Studio page ready at ' + studioPage.url()); + try{ + // wait for #status element that studio_receiver exposes + // try a slightly longer wait and fallback to scanning page text + try { + await studioPage.waitForSelector('#status', { timeout: 16000 }); + } catch (e) { + log('waitForSelector #status timed out, will fallback to scanning page content'); + } + const statusText = await studioPage.evaluate(() => { + const el = document.getElementById('status'); + if (el) return el.textContent; + return document.body ? document.body.innerText || document.body.textContent : null; + }).catch(()=>null); + log('Studio #status text (initial): ' + statusText); + } catch(e){ log('No #status element or timeout: ' + (e && e.message)); } + + // Now wait for the simulator page log (broadcast) to show ACK or for studio to update + try{ + // Wait up to 10s for ACK to appear in any page logs (simulator) or studio status + const ackStart = Date.now(); + let ackSeen = false; + const ackTimeout = 20000; // increase to 20s + while (!ackSeen && (Date.now() - ackStart) < ackTimeout){ + // check studio console logs first + try{ + for (const cmsg of studioConsoleLogs){ + if (cmsg && (cmsg.toLowerCase().includes('conectado') || cmsg.toLowerCase().includes('connected') || cmsg.toLowerCase().includes('ack'))) { + ackSeen = true; log('ACK/connected found in studio console logs: ' + cmsg); break; + } + } + }catch(e){} + + if (ackSeen) break; + + // check simulator page (first page) for log element + try{ + const simulatorPages = context.pages(); + for (const sp of simulatorPages){ + try{ + const content = await sp.evaluate(()=>{ + const el = document.getElementById('log'); + if (el && el.textContent) return el.textContent; + return document.body ? (document.body.innerText || document.body.textContent) : null; + }); + if (content && (content.includes('ACK') || /connected/i.test(content) || /conectado/i.test(content))) { ackSeen = true; log('ACK/connected found in simulator page content'); break; } + }catch(e){} + } + }catch(e){ } + + // also check studio status + try{ + const s = await studioPage.evaluate(()=>{ + const st = document.getElementById('status'); + if (st && st.textContent) return st.textContent; + return document.body ? (document.body.innerText || document.body.textContent) : null; + }); + if (s && (s.toLowerCase().includes('ack') || s.toLowerCase().includes('connected') || s.toLowerCase().includes('conectado'))) { ackSeen = true; log('ACK/connected found in studio content: '+s); } + }catch(e){} + + if (!ackSeen) await new Promise(r=>setTimeout(r, 300)); + } + + if (!ackSeen) log('Timeout waiting for ACK ('+ (ackTimeout/1000) +'s)'); + } catch(e){ log('Error while waiting for ACK: '+e); } + + // take screenshots + const simShot = '/tmp/sim_postmessage_simulator.png'; + const studioShot = '/tmp/sim_postmessage_studio.png'; + try{ await page.screenshot({ path: simShot, fullPage: true }); log('Saved simulator screenshot: ' + simShot); } catch(e){ log('Failed saving simulator screenshot: ' + e); } + try{ await studioPage.screenshot({ path: studioShot, fullPage: true }); log('Saved studio screenshot: ' + studioShot); } catch(e){ log('Failed saving studio screenshot: ' + e); } + } + + } catch (err) { + log('Unhandled error: ' + (err && err.stack ? err.stack : String(err))); + process.exitCode = 2; + } finally { + try { if (browser) await browser.close(); log('Browser closed'); } catch(e) { log('Error closing browser: ' + e); } + } + log('Test finished'); +})(); diff --git a/packages/studio-panel/scripts/playwright_rec_test.mjs b/packages/studio-panel/scripts/playwright_rec_test.mjs new file mode 100644 index 0000000..906a259 --- /dev/null +++ b/packages/studio-panel/scripts/playwright_rec_test.mjs @@ -0,0 +1,34 @@ +let playwright +try { playwright = await import('playwright'); } catch (e) { console.error('Playwright no está instalado:', e); process.exit(2); } +const { chromium } = playwright; +(async ()=>{ + const browser = await chromium.launch(); + const page = await browser.newPage(); + try{ + console.log('Navegando a simulate.html...'); + await page.goto('http://localhost:3021/simulate.html', { waitUntil: 'networkidle', timeout: 15000 }); + console.log('Página cargada. Buscando botón Start...'); + const btn = await page.waitForSelector('button#recBtn, button:has-text("Start")', { timeout: 5000 }); + if(!btn) throw new Error('Botón de grabación no encontrado'); + console.log('Haciendo click en Start...'); + await btn.click(); + // esperar a que la clase recording esté presente o a que el .record-dot sea visible + await page.waitForSelector('.btn-control.recording', { timeout: 5000 }); + await page.waitForSelector('.record-dot', { timeout: 5000 }); + console.log('Recording visuals present — tomando captura...'); + await page.screenshot({ path: '/tmp/studio_record_test.png', fullPage: true }); + console.log('Screenshot guardada en /tmp/studio_record_test.png'); + // comprobar atributos + const attrs = await page.evaluate(()=>{ + const btn = document.getElementById('recBtn'); + return { + ariaPressed: btn?.getAttribute('aria-pressed'), + hasRecordingClass: btn?.classList.contains('recording'), + recordDotDisplay: window.getComputedStyle(btn?.querySelector('.record-dot') || document.createElement('span')).display + } + }); + console.log('Atributos tras click:', JSON.stringify(attrs)); + }catch(e){ console.error('Error durante la prueba:', e); process.exitCode = 2 } + await browser.close(); +})(); + diff --git a/packages/studio-panel/scripts/pp_screenshot.mjs b/packages/studio-panel/scripts/pp_screenshot.mjs new file mode 100644 index 0000000..f7cc18a --- /dev/null +++ b/packages/studio-panel/scripts/pp_screenshot.mjs @@ -0,0 +1,14 @@ +let playwright +try { playwright = await import('playwright'); } catch (e) { console.error('playwright missing', e); process.exit(2); } +const { chromium } = playwright; +(async ()=>{ + const browser = await chromium.launch(); + const page = await browser.newPage(); + try{ + await page.goto('http://localhost:3021/', { waitUntil: 'networkidle' , timeout: 10000 }); + await page.screenshot({ path: '/tmp/studio_panel_home.png', fullPage: true }); + console.log('screenshot saved to /tmp/studio_panel_home.png'); + }catch(e){ console.error('err', e.toString()); process.exitCode=2 } + await browser.close(); +})(); + diff --git a/packages/studio-panel/src/App.tsx b/packages/studio-panel/src/App.tsx index 55c32b3..e034e47 100644 --- a/packages/studio-panel/src/App.tsx +++ b/packages/studio-panel/src/App.tsx @@ -1,7 +1,9 @@ -import React, { useState } from 'react'; -import { StudioRoom } from './components/StudioRoom/StudioRoom'; +import React, { useState, useEffect, useRef } from 'react'; import { Button } from 'avanza-ui'; import './App.css'; +import StudioPortal from './components/Portal/StudioPortal'; +import { isAllowedOrigin } from './utils/postMessage'; +import { Room } from 'livekit-client'; function App() { const [isConnected, setIsConnected] = useState(false); @@ -12,6 +14,131 @@ function App() { }); const [tempToken, setTempToken] = useState(''); + const autoAttemptRef = useRef(false); + // external LiveKit Room managed by App when token is received + const roomRef = useRef(null); + const messageSourceRef = useRef(null); + // store the last validated origin that sent a token so we can ACK securely + const lastValidatedOrigin = useRef(null); + + // Called when the LiveKit room reports connected + const handleRoomConnected = () => { + setIsConnected(true); + // send connected ACK to the validated origin if available + try { + const payload = { type: 'LIVEKIT_ACK', status: 'connected' }; + const targetOrigin = lastValidatedOrigin.current || '*'; + // Prefer replying directly to the message source window if available + if (messageSourceRef.current && typeof (messageSourceRef.current as any).postMessage === 'function') { + try { (messageSourceRef.current as any).postMessage(payload, targetOrigin); } catch (e) { /* ignore */ } + } + if (window.opener && !window.opener.closed) { + try { window.opener.postMessage(payload, targetOrigin); } catch (e) { /* ignore */ } + } + if (window.parent && window.parent !== window) { + try { window.parent.postMessage(payload, targetOrigin); } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore */ } + }; + + const handleRoomDisconnected = () => { + setIsConnected(false); + try { + const payload = { type: 'LIVEKIT_ACK', status: 'disconnected' }; + const targetOrigin = lastValidatedOrigin.current || '*'; + if (window.opener && !window.opener.closed) { + try { window.opener.postMessage(payload, targetOrigin); } catch (e) { /* ignore */ } + } + if (window.parent && window.parent !== window) { + try { window.parent.postMessage(payload, targetOrigin); } catch (e) { /* ignore */ } + } + } catch (e) {} + // disconnect and clear app-managed room + try { if (roomRef.current) { roomRef.current.disconnect(); roomRef.current = null; } } catch(e){} + }; + + // Cleanup app-managed room on unmount + useEffect(() => { + return () => { + try { if (roomRef.current) { roomRef.current.disconnect(); roomRef.current = null; } } catch(e){} + }; + }, []); + + // Listen for LIVEKIT_TOKEN posted via postMessage (handshake flow) + useEffect(() => { + // central token handler used by both message events and custom events + const handleIncomingToken = async (payload: any, origin?: string | null, source?: any) => { + try { + const originToUse = origin || null; + if (!isAllowedOrigin(originToUse)) { + return; + } + // store validated origin and message source for ACKs + if (originToUse) lastValidatedOrigin.current = originToUse; + if (source) messageSourceRef.current = source; + + if (payload?.url) setCredentials(prev => ({ ...prev, serverUrl: String(payload.url) })); + const receivedToken = String(payload.token || payload?.token); + setTempToken(receivedToken); + + // cleanup previous room if exists + try { if (roomRef.current) { roomRef.current.disconnect(); roomRef.current = null; } } catch(e){} + + const newRoom = new Room(); + roomRef.current = newRoom; + try { + const sUrl = payload?.url || credentials.serverUrl; + await newRoom.connect(sUrl, receivedToken); + setCredentials(prev => ({ ...prev, token: receivedToken })); + handleRoomConnected(); + } catch (err) { + console.error('App-managed room connect failed', err); + } + + if (!autoAttemptRef.current) { + autoAttemptRef.current = true; + setTimeout(() => { if (receivedToken) handleConnectWithToken(receivedToken); }, 60); + } + } catch (err) { console.debug('handleIncomingToken error', err); } + }; + + function onMessage(e: MessageEvent) { + try { + const d = e.data || {}; + if (d?.type === 'LIVEKIT_TOKEN' && d.token) { + // call central handler and pass origin/source + handleIncomingToken(d, e.origin || null, e.source); + } + } catch (err) { console.debug('postMessage in App error', err) } + } + window.addEventListener('message', onMessage); + + // Also listen for the custom event dispatched by main.tsx + function onCustomToken(e: any) { + try { + const detail = e?.detail || (window as any).__AVANZACAST_PENDING_TOKEN || null; + // attempt to recover origin/source from globals set by main.tsx if present + const lastMsg = (window as any).__AVZ_LAST_MSG_SOURCE || null; + const origin = lastMsg?.origin || null; + const source = lastMsg?.source || null; + if (detail && detail.token) handleIncomingToken(detail, origin, source); + } catch(err) { console.debug('custom token handler error', err); } + } + window.addEventListener('avz:livekit:token', onCustomToken as EventListener); + + return () => { + window.removeEventListener('message', onMessage); + window.removeEventListener('avz:livekit:token', onCustomToken as EventListener); + }; + }, []); + + + function handleConnectWithToken(tokenVal: string) { + if (tokenVal && tokenVal.trim()) { + setCredentials(prev => ({ ...prev, token: tokenVal })); + setIsConnected(true); + } + } const handleConnect = () => { if (tempToken.trim()) { @@ -20,6 +147,37 @@ function App() { } }; + // Update a global #status element and notify opener/parent when connected — helps E2E tests detect ACK/state + useEffect(() => { + try { + const setStatus = (txt: string) => { + try { + let el = document.getElementById('status'); + if (!el) { + el = document.createElement('div'); + el.id = 'status'; + el.style.position = 'fixed'; + el.style.right = '12px'; + el.style.top = '12px'; + el.style.padding = '8px 12px'; + el.style.background = 'rgba(16,185,129,0.12)'; + el.style.color = '#10B981'; + el.style.borderRadius = '6px'; + el.style.zIndex = '9999'; + document.body.appendChild(el); + } + el.textContent = txt; + } catch (e) { /* ignore */ } + }; + + if (isConnected) { + setStatus('Conectado'); + } else { + setStatus('Esperando token...'); + } + } catch (e) {} + }, [isConnected]); + if (!isConnected) { return (
console.log('Conectado a la sala')} - onDisconnected={() => { - console.log('Desconectado de la sala'); - setIsConnected(false); - }} + onRoomConnected={handleRoomConnected} + onRoomDisconnected={handleRoomDisconnected} + room={roomRef.current || undefined} /> ); } export default App; - diff --git a/packages/studio-panel/src/__tests__/StudioPortal.test.tsx b/packages/studio-panel/src/__tests__/StudioPortal.test.tsx new file mode 100644 index 0000000..f6c3268 --- /dev/null +++ b/packages/studio-panel/src/__tests__/StudioPortal.test.tsx @@ -0,0 +1,61 @@ +import React from 'react' +import { render, screen, waitFor, fireEvent } from '@testing-library/react' +import { vi, describe, it, expect, beforeEach } from 'vitest' + +// Mock livekit-client Room class +const connectMock = vi.fn(() => Promise.resolve()) +const disconnectMock = vi.fn(() => {}) +const mockRoomConstructor = vi.fn(() => ({ connect: connectMock, disconnect: disconnectMock })) + +vi.mock('livekit-client', () => { + return { Room: mockRoomConstructor } +}) + +import StudioPortal from '../components/Portal/StudioPortal' + +describe('StudioPortal', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('creates a local Room and connects when token is provided and no external room', async () => { + render() + + // wait for the connect to be called + await waitFor(() => { + expect(mockRoomConstructor).toHaveBeenCalled() + expect(connectMock).toHaveBeenCalledWith('wss://example', 'FAKE_TOKEN') + }) + }) + + it('does not create a local Room when external room is provided', async () => { + const fakeRoom = { connect: vi.fn(), disconnect: vi.fn() } + render() + + // local constructor should not be called + await new Promise((r) => setTimeout(r, 50)) + expect(mockRoomConstructor).not.toHaveBeenCalled() + }) + + it('connect/disconnect buttons call connectWithToken and disconnect', async () => { + // render without auto token to test manual connect: pass empty token first + const { rerender } = render() + + // Click connect button -> nothing happens since token empty, ensure no constructor called + const connectBtn = screen.getByText(/Conectar|Conectando...|Conectado/, { exact: false }) + fireEvent.click(connectBtn) + expect(mockRoomConstructor).not.toHaveBeenCalled() + + // Rerender with token to enable connect via button + rerender() + + // Wait for auto connect (effect) or click button to trigger connect + await waitFor(() => expect(mockRoomConstructor).toHaveBeenCalled()) + + // Now test disconnect button triggers disconnect + const disconnectBtn = screen.getByText('Desconectar') + fireEvent.click(disconnectBtn) + await waitFor(() => expect(disconnectMock).toHaveBeenCalled()) + }) +}) + diff --git a/packages/studio-panel/src/__tests__/postMessage.test.ts b/packages/studio-panel/src/__tests__/postMessage.test.ts new file mode 100644 index 0000000..dcfaa19 --- /dev/null +++ b/packages/studio-panel/src/__tests__/postMessage.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect, vi } from 'vitest'; + +// We'll dynamically import the module after stubbing import.meta.env +async function loadWithEnv(env: Record) { + // stub import.meta for the module loader + // vitest allows stubbing globals; set globalThis.import = { meta: { env } } may work + // Save original + const origImportMeta = (globalThis as any).importMeta; + try { + (globalThis as any).importMeta = { env }; + const mod = await import('../utils/postMessage'); + return mod; + } finally { + (globalThis as any).importMeta = origImportMeta; + } +} + +describe('postMessage utils', () => { + it('reads allowed origins from VITE_STUDIO_ALLOWED_ORIGINS and VITE_STUDIO_URL', async () => { + const env = { + VITE_STUDIO_ALLOWED_ORIGINS: 'https://a.example.com, https://b.example.com', + VITE_STUDIO_URL: 'https://studio.example.com' + }; + const mod = await loadWithEnv(env as any); + const allowed = (mod.getAllowedOriginsFromEnv && mod.getAllowedOriginsFromEnv()) || []; + expect(allowed).toEqual(expect.arrayContaining(['https://a.example.com', 'https://b.example.com', 'https://studio.example.com'])); + }); + + it('isAllowedOrigin returns true for allowed origins and false otherwise', async () => { + const env = { VITE_STUDIO_ALLOWED_ORIGINS: 'https://x.com', VITE_STUDIO_URL: 'https://studio.local' }; + const mod = await loadWithEnv(env as any); + expect(mod.isAllowedOrigin('https://x.com')).toBe(true); + expect(mod.isAllowedOrigin('https://studio.local')).toBe(true); + expect(mod.isAllowedOrigin('https://notallowed.com')).toBe(false); + }); +}); + diff --git a/packages/studio-panel/src/__tests__/smoke.test.tsx b/packages/studio-panel/src/__tests__/smoke.test.tsx new file mode 100644 index 0000000..f02ed5e --- /dev/null +++ b/packages/studio-panel/src/__tests__/smoke.test.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { render, waitFor } from '@testing-library/react' +import { vi, describe, it, expect, beforeEach } from 'vitest' + +// Mock livekit-client Room +const connectMock = vi.fn(() => Promise.resolve()) +const disconnectMock = vi.fn() +const MockRoom = vi.fn(() => ({ connect: connectMock, disconnect: disconnectMock })) +vi.mock('livekit-client', () => ({ Room: MockRoom })) + +import App from '../App' + +describe('smoke test - App postMessage -> Studio', () => { + beforeEach(() => { + vi.clearAllMocks() + // ensure a clean DOM for status element + document.body.innerHTML = '' + }) + + it('accepts LIVEKIT_TOKEN postMessage and shows Conectado status', async () => { + render() + + // simulate sender posting message from same-origin + const payload = { type: 'LIVEKIT_TOKEN', token: 'SMOKE_TOKEN', url: 'wss://example' } + window.dispatchEvent(new MessageEvent('message', { data: payload, origin: window.location.origin, source: window })) + + // wait for status element textContent to become 'Conectado' + await waitFor(() => { + const el = document.getElementById('status') + expect(el).toBeTruthy() + expect(el?.textContent).toMatch(/Conectado/i) + }, { timeout: 3000 }) + + // ensure we constructed a Room and called connect + expect(MockRoom).toHaveBeenCalled() + expect(connectMock).toHaveBeenCalledWith('wss://example', 'SMOKE_TOKEN') + }) +}) + diff --git a/packages/studio-panel/src/components/BottomControls.tsx b/packages/studio-panel/src/components/BottomControls.tsx index f26063c..05ab87a 100644 --- a/packages/studio-panel/src/components/BottomControls.tsx +++ b/packages/studio-panel/src/components/BottomControls.tsx @@ -1,16 +1,178 @@ -import React from 'react' +import React, { useState, useContext } from 'react' import IconCameraOn from './icons/IconCameraOn' import IconMicOff from './icons/IconMicOff' +import { RoomContext } from '@livekit/components-react' +import { Room } from 'livekit-client' +import { ControlButton, ControlGroup, IconButton } from 'avanza-ui' + +interface BottomControlsProps { + onToggleMute?: (muted: boolean) => void; + onToggleCamera?: (cameraOn: boolean) => void; + onToggleRecording?: (recording: boolean) => void; +} + +let idCounter = 0 +function uniqueId(prefix = 'id'){ + idCounter += 1 + return `${prefix}-${idCounter}` +} + +export default function BottomControls({ onToggleMute, onToggleCamera, onToggleRecording }: BottomControlsProps){ + const [muted, setMuted] = useState(false) + const [cameraOn, setCameraOn] = useState(true) + const [recording, setRecording] = useState(false) + + // Try to obtain the LiveKit Room from context when available + const ctxRoom = useContext(RoomContext) as Room | null + + // Listen for go-live events to reflect live status in controls (no recording logic here) + React.useEffect(() => { + function onGoLive(e: any) { + try { + const d = e?.detail || {}; + if (d.action === 'start') setRecording(true); + else if (d.action === 'stop') setRecording(false); + } catch (err) { console.warn('go-live handler error', err) } + } + window.addEventListener('avz:request:go-live', onGoLive as EventListener); + return () => window.removeEventListener('avz:request:go-live', onGoLive as EventListener); + }, []); + + // Pre-generate tooltip ids so aria-describedby can reference them + const muteTipId = React.useMemo(() => uniqueId('tip-mute'), []) + const camTipId = React.useMemo(() => uniqueId('tip-cam'), []) + const recTipId = React.useMemo(() => uniqueId('tip-rec'), []) + + const safeSetMic = async (enabled: boolean) => { + try { + const r = ctxRoom as any + if (!r) return + const lp = r.localParticipant + if (!lp) return + if (typeof lp.setMicrophoneEnabled === 'function') { + await lp.setMicrophoneEnabled(enabled) + return + } + // fallback: enable/disable tracks + if (lp.audioTracks && Array.isArray(lp.audioTracks)) { + for (const tpub of lp.audioTracks) { + try { tpub.track && typeof tpub.track.enable === 'function' && tpub.track.enable(enabled) } catch(e){} + } + } + } catch (e) { + console.warn('safeSetMic failed', e) + } + } + + const safeSetCamera = async (enabled: boolean) => { + try { + const r = ctxRoom as any + if (!r) return + const lp = r.localParticipant + if (!lp) return + if (typeof lp.setCameraEnabled === 'function') { + await lp.setCameraEnabled(enabled) + return + } + if (lp.videoTracks && Array.isArray(lp.videoTracks)) { + for (const tpub of lp.videoTracks) { + try { tpub.track && typeof tpub.track.enable === 'function' && tpub.track.enable(enabled) } catch(e){} + } + } + } catch (e) { + console.warn('safeSetCamera failed', e) + } + } + + const safeToggleRecording = async (start: boolean) => { + try { + const r = ctxRoom as any + if (!r) return + const lp = r.localParticipant + if (!lp) return + // Try to publish a data message as a recording signal (best-effort) + if (typeof lp.publishData === 'function') { + const payload = JSON.stringify({ type: 'RECORDING', action: start ? 'start' : 'stop', ts: Date.now() }) + const enc = new TextEncoder().encode(payload) + try { await lp.publishData(enc, { reliable: true }) } catch(e) { console.warn('publishData failed', e) } + return + } + // If publishData not available, try room.broadcast... (best-effort) + if (typeof r.sendData === 'function') { + try { r.sendData(JSON.stringify({ type: 'RECORDING', action: start ? 'start' : 'stop' })) } catch(e) {} + } + } catch (e) { + console.warn('safeToggleRecording failed', e) + } + } + + const handleToggleMute = async () => { + const next = !muted + setMuted(next) + onToggleMute?.(next) + // Try to control livekit + await safeSetMic(!next ? true : false) // note: muted=true means microphone disabled + } + + const handleToggleCamera = async () => { + const next = !cameraOn + setCameraOn(next) + onToggleCamera?.(next) + await safeSetCamera(next) + } + + const handleToggleRecording = async () => { + const next = !recording + setRecording(next) + onToggleRecording?.(next) + // no-op for recording when focusing on transmission + } -export default function BottomControls(){ return ( -
-
- - - -
+
+ + +
+ } + active={!muted} + title={muted ? 'Activar micrófono' : 'Silenciar'} + onClick={handleToggleMute} + size="sm" + /> + {muted ? 'Activar micrófono' : 'Silenciar'} +
+ +
+ } + active={cameraOn} + title={cameraOn ? 'Apagar cámara' : 'Encender cámara'} + onClick={handleToggleCamera} + size="sm" + /> + {cameraOn ? 'Apagar cámara' : 'Encender cámara'} +
+ +
+ : undefined} + label={recording ? 'Stop' : 'Start'} + active={recording} + danger={true} + title={recording ? 'Detener grabación' : 'Iniciar grabación'} + onClick={handleToggleRecording} + size="md" + /> + {recording ? 'Detener grabación' : 'Iniciar grabación'} +
+ + {recording ? 'Grabación iniciada' : 'Grabación detenida'} + +
) } - diff --git a/packages/studio-panel/src/components/ChatPanel.tsx b/packages/studio-panel/src/components/ChatPanel.tsx index 559bd6e..cbc7386 100644 --- a/packages/studio-panel/src/components/ChatPanel.tsx +++ b/packages/studio-panel/src/components/ChatPanel.tsx @@ -18,7 +18,12 @@ export function ChatPanel() { // Auto-scroll to bottom when messages change const el = listRef.current if (el) { - el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }) + if (typeof el.scrollTo === 'function') { + el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }) + } else { + // Fallback for environments like jsdom that don't implement scrollTo + el.scrollTop = el.scrollHeight + } } }, [messages]) @@ -131,7 +136,6 @@ export function ChatPanel() { type="submit" variant="primary" size="sm" - onClick={send} style={{ background: 'linear-gradient(135deg, #4361ee 0%, #3651d4 100%)', border: 'none', diff --git a/packages/studio-panel/src/components/LivekitConnector.tsx b/packages/studio-panel/src/components/LivekitConnector.tsx index 83e5c19..d575949 100644 --- a/packages/studio-panel/src/components/LivekitConnector.tsx +++ b/packages/studio-panel/src/components/LivekitConnector.tsx @@ -2,12 +2,155 @@ import React, { useEffect, useRef, useState } from 'react' import { Button, Input, Badge } from 'avanza-ui' export function LivekitConnector() { - const [url, setUrl] = useState('') - const [token, setToken] = useState('') + // Compatibilidad: priorizamos VITE_LIVEKIT_WS_URL (broadcast-panel), luego VITE_LIVEKIT_URL, luego window global + const defaultUrl = (import.meta.env.VITE_LIVEKIT_WS_URL as string) || (import.meta.env.VITE_LIVEKIT_URL as string) || (window as any).__LIVEKIT_URL__ || '' + // Compatibilidad para token server: VITE_TOKEN_SERVER_URL (broadcast-panel) o VITE_BACKEND_URL + const backendBase = (import.meta.env.VITE_TOKEN_SERVER_URL as string) || (import.meta.env.VITE_BACKEND_URL as string) || 'http://localhost:4000' + const [url, setUrl] = useState(defaultUrl) + const [token, setToken] = useState('') const [status, setStatus] = useState<'idle'|'connecting'|'connected'|'error'>('idle') const roomRef = useRef(null) const [participants, setParticipants] = useState([]) + // Refs to support postMessage ACK back to the opener + const messageSourceRef = useRef(null) + const messageOriginRef = useRef(null) + const lastPayloadRef = useRef(null) + const autoAttemptedRef = useRef(false) + + // Local helper fields for requesting token from backend + const [requestRoom, setRequestRoom] = useState('studio-demo') + const [requestUsername, setRequestUsername] = useState(() => { + try { return (sessionStorage.getItem('username') as string) || 'guest' } catch (e) { return 'guest' } + }) + const [isRequestingToken, setIsRequestingToken] = useState(false) + const [errorMessage, setErrorMessage] = useState(null) + const [isFetchingSessionById, setIsFetchingSessionById] = useState(false) + + useEffect(() => { + // Try to read token from query param ?token=... + try { + const params = new URLSearchParams(window.location.search) + const qtoken = params.get('token') + const qserver = params.get('serverUrl') + const qroom = params.get('room') + const quser = params.get('username') + if (qserver) setUrl(qserver) + if (qroom) setRequestRoom(qroom) + if (quser) setRequestUsername(quser) + if (qtoken) { + setToken(qtoken) + // Auto-connect immediately using defaultUrl (env) or current url state + setTimeout(() => { + try { connectToLivekit(qserver || defaultUrl || undefined, qtoken) } catch (e) { console.debug('[LivekitConnector] auto connect error', e) } + }, 20) + } + } catch (e) { console.debug('[LivekitConnector] query parse error', e) } + + // Detect a sessionId embedded in the path (e.g. /abc1234) and fetch its token from backend + try { + const pathname = window.location.pathname || '/' + const parts = pathname.split('/').filter(Boolean) + if (parts.length === 1) { + const candidate = parts[0] + // session ids generated by backend are alphanumeric short strings (7 chars by default) + if (/^[a-z0-9]{5,20}$/i.test(candidate)) { + // fetch session info from backend + const sessionId = candidate + ;(async () => { + try { + setIsFetchingSessionById(true) + setErrorMessage(null) + const resp = await fetch(`${backendBase.replace(/\/$/, '')}/api/session/${encodeURIComponent(sessionId)}`, { method: 'GET' }) + if (!resp.ok) { + const text = await resp.text() + console.warn('[LivekitConnector] session fetch failed', resp.status, text) + setErrorMessage(`No fue posible obtener la sesión: HTTP ${resp.status}`) + setIsFetchingSessionById(false) + return + } + const data = await resp.json() + if (data?.token) { + if (data.url) setUrl(String(data.url)) + if (data.room) setRequestRoom(String(data.room)) + if (data.username) setRequestUsername(String(data.username)) + setToken(String(data.token)) + // Best-effort: mark session as consumed to reduce replay risk + ;(async () => { + try { + await fetch(`${backendBase.replace(/\/$/, '')}/api/session/${encodeURIComponent(sessionId)}/consume`, { method: 'POST' }) + console.debug('[LivekitConnector] session consume requested') + } catch (consumeErr) { + console.debug('[LivekitConnector] session consume failed', consumeErr) + } + })() + // auto connect + if (!autoAttemptedRef.current) { + autoAttemptedRef.current = true + setTimeout(() => { + try { connectToLivekit(data.url || defaultUrl, data.token) } catch (err) { console.debug('[LivekitConnector] session fetch connect error', err) } + }, 30) + } + } else { + setErrorMessage('Respuesta inválida al solicitar la sesión') + } + } catch (err) { + console.error('[LivekitConnector] Error fetching session by id', err) + setErrorMessage(`Error al obtener la sesión: ${String(err)}`) + } finally { + setIsFetchingSessionById(false) + } + })() + } + } + } catch (e) { console.debug('[LivekitConnector] path session detection error', e) } + + // Listen for messages (broadcast-panel can postMessage the token) + function onMessage(e: MessageEvent) { + if (!e?.data) return + const data = e.data + // Respond to ping from opener / broadcast to indicate app is ready + if (data?.type === 'LIVEKIT_PING') { + try { + // reply to the source with READY so opener can safely send token + if (e.source && typeof (e.source as any).postMessage === 'function') { + try { (e.source as any).postMessage({ type: 'LIVEKIT_READY' }, e.origin || '*') } catch (err) { console.debug('[LivekitConnector] PING reply failed', err) } + } else if (window.opener && typeof (window.opener as any).postMessage === 'function') { + try { (window.opener as any).postMessage({ type: 'LIVEKIT_READY' }, e.origin || '*') } catch (err) { console.debug('[LivekitConnector] PING reply to opener failed', err) } + } + } catch (err) { console.debug('[LivekitConnector] ping handling error', err) } + } + if (data?.type === 'LIVEKIT_TOKEN') { + // Store source/origin and payload so we can ACK back after connect + try { + messageSourceRef.current = e.source || (window.opener || null) + } catch (err) { + messageSourceRef.current = (window.opener || null) + } + messageOriginRef.current = (e.origin as string) || null + lastPayloadRef.current = data + + if (data?.url) setUrl(data.url) + if (data?.token) setToken(data.token) + + // auto connect if both present (debounced) + if (data.token && (data.url || defaultUrl)) { + if (!autoAttemptedRef.current) { + autoAttemptedRef.current = true + setTimeout(() => { + try { connectToLivekit(data.url || defaultUrl, data.token) } catch (err) { console.debug('[LivekitConnector] postMessage connect error', err) } + }, 30) + } else { + console.debug('[LivekitConnector] auto connect already attempted, ignoring duplicate token') + } + } + } + } + + window.addEventListener('message', onMessage) + return () => window.removeEventListener('message', onMessage) + }, []) + useEffect(() => { return () => { if (roomRef.current?.disconnect) { @@ -16,66 +159,148 @@ export function LivekitConnector() { } }, []) - async function connectToLivekit() { + // Try auto-connect if token/url become available and we haven't tried yet + useEffect(() => { + if (!autoAttemptedRef.current && token && (url || defaultUrl)) { + autoAttemptedRef.current = true + setTimeout(() => { + try { connectToLivekit(url || defaultUrl, token) } catch (e) { console.debug('[LivekitConnector] auto connect effect error', e) } + }, 50) + } + }, [token, url]) + + async function requestTokenFromBackend(roomName?: string, username?: string) { + const room = roomName || requestRoom + const user = username || requestUsername + if (!room || !user) return + setIsRequestingToken(true) + setErrorMessage(null) + setStatus('connecting') + + try { + const urlReq = `${backendBase.replace(/\/$/, '')}/api/token?room=${encodeURIComponent(room)}&username=${encodeURIComponent(user)}` + const res = await fetch(urlReq, { method: 'GET' }) + const data = await res.json() + if (!res.ok) { + const msg = (data && data.error) ? String(data.error) : `HTTP ${res.status}` + console.error('Token request error', msg) + setErrorMessage(`Error obteniendo token: ${msg}`) + setStatus('error') + setIsRequestingToken(false) + return + } + + if (data.token) { + if (data.url) setUrl(data.url) + setToken(data.token) + // auto connect + if (!autoAttemptedRef.current) { + autoAttemptedRef.current = true + setTimeout(() => connectToLivekit(data.url || defaultUrl, data.token), 20) + } + setIsRequestingToken(false) + setErrorMessage(null) + return + } + + console.error('Unexpected token response', data) + setErrorMessage('Respuesta inesperada del servidor al solicitar token') + setStatus('error') + setIsRequestingToken(false) + } catch (err) { + console.error('Failed requesting token', err) + setErrorMessage(`Fallo al solicitar token: ${String(err)}`) + setStatus('error') + setIsRequestingToken(false) + } + } + + async function connectToLivekit(overrideUrl?: string, overrideToken?: string) { + const connectUrl = overrideUrl || url + const connectToken = overrideToken || token + if (!connectUrl || !connectToken) { + setStatus('error') + console.warn('Missing LiveKit URL or token') + return + } + setStatus('connecting') setParticipants([]) + try { const mod = await import('livekit-client') const lk: any = (mod as any).default ? (mod as any).default : mod - const connectFn = lk && (lk.connect || lk.createRoom || lk.Room || null) - if (!connectFn) { - setStatus('error') - console.warn('LiveKit client not available (no connect/createRoom)') - return - } - let room: any = null + // Prefer connect(url, token) if available if (typeof lk.connect === 'function') { - room = await lk.connect(url, token) - } else if (typeof lk.createRoom === 'function') { - room = await lk.createRoom() - if (room && typeof room.connect === 'function') { - await room.connect(url, token) - } - } else if (lk.Room) { - room = new lk.Room() - if (room && typeof room.connect === 'function') { - await room.connect(url, token) - } - } + const room = await lk.connect(connectUrl, connectToken) + roomRef.current = room + setStatus('connected') - if (!room) { - setStatus('error') - console.warn('Could not create or connect to LiveKit Room') + // NOTE: Do not send LIVEKIT_ACK here; App will centralize ACK sending to avoid duplicates. + + const updateParticipants = () => { + try { + const parts: any[] = [] + if (room.participants && typeof room.participants.values === 'function') { + for (const p of room.participants.values()) { + parts.push({ sid: p.sid, identity: p.identity, participant: p }) + } + } else if (Array.isArray(room.participants)) { + for (const p of room.participants) parts.push(p) + } + setParticipants(parts) + } catch (e) { + console.warn('updateParticipants error', e) + } + } + + room.on?.('participantConnected', updateParticipants) + room.on?.('participantDisconnected', updateParticipants) + room.on?.('trackPublished', updateParticipants) + updateParticipants() return } - roomRef.current = room - setStatus('connected') + // Fallback: try Room class + if (lk.Room) { + const RoomClass = lk.Room + const room = new RoomClass() + if (room && typeof room.connect === 'function') { + await room.connect(connectUrl, connectToken) + roomRef.current = room + setStatus('connected') - const updateParticipants = () => { - try { - const parts: any[] = [] - if (room.participants && typeof room.participants.values === 'function') { - for (const p of room.participants.values()) { - parts.push({ sid: p.sid, identity: p.identity, participant: p }) - } - } else if (Array.isArray(room.participants)) { - for (const p of room.participants) parts.push(p) + // NOTE: Do not send LIVEKIT_ACK here; App will centralize ACK sending to avoid duplicates. + + const updateParticipants = () => { + try { + const parts: any[] = [] + if (room.participants && typeof room.participants.values === 'function') { + for (const p of room.participants.values()) parts.push({ sid: p.sid, identity: p.identity, participant: p }) + } else if (Array.isArray(room.participants)) { + for (const p of room.participants) parts.push(p) + } + setParticipants(parts) + } catch (e) {} } - setParticipants(parts) - } catch (e) { + room.on?.('participantConnected', updateParticipants) + room.on?.('participantDisconnected', updateParticipants) + room.on?.('trackPublished', updateParticipants) + updateParticipants() + return } } - room.on?.('participantConnected', updateParticipants) - room.on?.('participantDisconnected', updateParticipants) - room.on?.('trackPublished', updateParticipants) - updateParticipants() + setStatus('error') + console.warn('LiveKit client did not expose a known connect API') } catch (err) { setStatus('error') console.error('LiveKit connect error', err) + + // NOTE: Do not send LIVEKIT_ACK/error here; App will centralize ACK sending. + } } @@ -103,6 +328,29 @@ export function LivekitConnector() { style={{ marginBottom: 'var(--au-spacing-2)' }} /> + {isFetchingSessionById && ( +
Obteniendo sesión desde el servidor...
+ )} + +
+ ) => setRequestRoom(e.target.value)} + placeholder="Room name" + size="sm" + style={{ flex: 1 }} + /> + ) => setRequestUsername(e.target.value)} + placeholder="Username" + size="sm" + style={{ width: '180px' }} + /> +
+
- +
+ {errorMessage && ( +
+ {errorMessage} +
+ )} +
Estado: void; + onRoomDisconnected?: () => void; + /** optional external LiveKit Room instance */ + room?: any; +} + +const LAYOUTS = [ + { id: 'layout-1', label: 'Individual' }, + { id: 'layout-2', label: 'Gallery' }, + { id: 'layout-3', label: 'Speaker' }, + { id: 'layout-4', label: 'Wide' }, +]; + +export default function StudioPortal({ serverUrl, token, roomName, onRoomConnected, onRoomDisconnected, room }: StudioPortalProps) { + const [activeLayout, setActiveLayout] = useState(LAYOUTS[0].id); + const [live, setLive] = useState(false); + + // Local room management when App does not provide a room prop + const localRoomRef = useRef(null); + const [isConnecting, setIsConnecting] = useState(false); + const [isConnected, setIsConnected] = useState(false); + const isExternalRoom = Boolean(room); + + // Connect function used by UI or auto when token arrives + const connectWithToken = async (useToken?: string, useServer?: string) => { + const tk = useToken || token; + const sUrl = useServer || serverUrl; + if (!tk || !sUrl) return; + try { + setIsConnecting(true); + // cleanup previous + if (localRoomRef.current) { + try { localRoomRef.current.disconnect(); } catch(e) {} + localRoomRef.current = null; + } + const r = new Room(); + localRoomRef.current = r; + await r.connect(sUrl, tk); + setIsConnected(true); + onRoomConnected && onRoomConnected(); + } catch (err) { + console.error('StudioPortal: failed to connect local room', err); + setIsConnected(false); + } finally { + setIsConnecting(false); + } + }; + + const disconnectLocalRoom = () => { + try { + if (localRoomRef.current) { + localRoomRef.current.disconnect(); + localRoomRef.current = null; + } + } catch (e) { /* ignore */ } + setIsConnected(false); + onRoomDisconnected && onRoomDisconnected(); + }; + + // Auto-connect when token becomes available and there is no external room + useEffect(() => { + if (!isExternalRoom && token && token.trim() && !isConnected && !isConnecting) { + connectWithToken(token, serverUrl); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [token, serverUrl]); + + // Cleanup on unmount + useEffect(() => { + return () => { + try { if (localRoomRef.current) { localRoomRef.current.disconnect(); localRoomRef.current = null; } } catch (e) {} + }; + }, []); + + const handleStartLive = () => { + window.dispatchEvent(new CustomEvent('avz:request:go-live', { detail: { action: 'start' } })); + setLive(true); + }; + const handleStopLive = () => { + window.dispatchEvent(new CustomEvent('avz:request:go-live', { detail: { action: 'stop' } })); + setLive(false); + }; + + const changeLayout = (id: string) => { + setActiveLayout(id); + try { + window.dispatchEvent(new CustomEvent('avz:layout:change', { detail: { layoutId: id } })); + } catch (e) { console.warn('layout dispatch failed', e); } + }; + + // Determine which room to pass into StudioRoom: external first, fallback to local + const effectiveRoom = room || localRoomRef.current || undefined; + + return ( +
+ + +
+
+
+ LiveKit: {serverUrl} +
+
+ {!isExternalRoom && ( + <> + + + + )} + {isExternalRoom && ( +
Usando Room externo
+ )} +
+
+ +
+ +
+ +
+
+ {LAYOUTS.map(l => ( + + ))} +
+ +
+ {!live ? ( + + ) : ( + + )} +
+
+
+ + +
+ ); +} diff --git a/packages/studio-panel/src/components/StudioRoom/StudioRoom.css b/packages/studio-panel/src/components/StudioRoom/StudioRoom.css index 78c7275..abe90ef 100644 --- a/packages/studio-panel/src/components/StudioRoom/StudioRoom.css +++ b/packages/studio-panel/src/components/StudioRoom/StudioRoom.css @@ -191,6 +191,35 @@ padding: var(--studio-space-lg); } +/* Floating bottom controls overrides to mimic StreamYard center placement */ +.fixed.bottom-4.left-4.right-4 { + left: 0 !important; + right: 0 !important; + display: flex; + justify-content: center; + pointer-events: none; /* inner controls manage pointer events */ + z-index: 1200; +} + +.fixed.bottom-4.left-4.right-4 .controls-inner { + pointer-events: auto; +} + +/* ensure the record button stands out */ +.btn-control--danger { + background: linear-gradient(180deg, var(--studio-recording) 0%, #d43a3a 100%); + border: none; +} + +/* smaller screens: place controls inset to the right */ +@media (max-width: 480px) { + .fixed.bottom-4.left-4.right-4 { + left: 12px !important; + right: 12px !important; + justify-content: flex-end; + } +} + /* Responsive */ @media (max-width: 768px) { .studio-room__header { @@ -214,3 +243,62 @@ } } +/* Layout presets applied via .studio-room[data-layout="..."] */ + +/* Layout 1: large single speaker */ +.studio-room[data-layout="layout-1"] .lk-grid-layout { + display: flex !important; + align-items: center; + justify-content: center; +} +.studio-room[data-layout="layout-1"] .lk-participant-tile { + width: 80% !important; + height: 80% !important; + max-width: 1200px; +} + +/* Layout 2: gallery (4-up) */ +.studio-room[data-layout="layout-2"] .lk-grid-layout { + display: flex !important; + flex-wrap: wrap !important; + align-items: stretch !important; + justify-content: flex-start !important; + gap: 12px !important; +} +.studio-room[data-layout="layout-2"] .lk-participant-tile { + flex: 0 0 calc(25% - 12px) !important; + height: calc(50% - 12px) !important; + max-width: none !important; +} + +/* Layout 3: speaker + row of participants */ +.studio-room[data-layout="layout-3"] .lk-grid-layout { + display: grid !important; + grid-template-columns: 1fr 320px !important; + gap: 12px !important; +} +.studio-room[data-layout="layout-3"] .lk-participant-tile:first-of-type { + grid-column: 1 / 2 !important; + width: 100% !important; +} +.studio-room[data-layout="layout-3"] .lk-participant-tile:not(:first-of-type) { + grid-column: 2 / 3 !important; + width: 100% !important; + height: auto !important; +} + +/* Layout 4: wide presenter with sidebar */ +.studio-room[data-layout="layout-4"] .lk-grid-layout { + display: grid !important; + grid-template-columns: 1fr 280px !important; + gap: 12px !important; +} +.studio-room[data-layout="layout-4"] .lk-participant-tile { + width: 100% !important; + height: 100% !important; +} + +/* Fallback small adjustments to ensure responsive behavior */ +.studio-room[data-layout] .lk-participant-tile { + transition: transform 220ms ease, width 220ms ease, height 220ms ease; +} diff --git a/packages/studio-panel/src/components/StudioRoom/StudioRoom.tsx b/packages/studio-panel/src/components/StudioRoom/StudioRoom.tsx index 27dbf9c..c93f2f2 100644 --- a/packages/studio-panel/src/components/StudioRoom/StudioRoom.tsx +++ b/packages/studio-panel/src/components/StudioRoom/StudioRoom.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from 'react'; import { - LiveKitRoom, GridLayout, ParticipantTile, ControlBar, @@ -12,6 +11,7 @@ import { Room, Track } from 'livekit-client'; import '@livekit/components-styles'; import { Button } from 'avanza-ui'; import './StudioRoom.css'; +import BottomControls from '../BottomControls'; export interface StudioRoomProps { /** LiveKit server URL */ @@ -24,6 +24,8 @@ export interface StudioRoomProps { onConnected?: () => void; /** Callback when room is disconnected */ onDisconnected?: () => void; + /** Optional externally-created LiveKit Room instance */ + room?: Room; } export const StudioRoom: React.FC = ({ @@ -32,36 +34,235 @@ export const StudioRoom: React.FC = ({ roomName, onConnected, onDisconnected, + room: externalRoom, }) => { - const [room] = useState( - () => - new Room({ - adaptiveStream: true, - dynacast: true, - }) + // If an external Room is provided, use it; otherwise create an internal Room instance + const [internalRoom] = useState(() => new Room({ adaptiveStream: true, dynacast: true })); + const room = externalRoom || internalRoom; + const isExternalRoom = !!externalRoom; + const [connectError, setConnectError] = useState(null); + const [participantsList, setParticipantsList] = useState>([]); + const connectedRef = React.useRef(false); + const connectingRef = React.useRef(false); + const previewRef = React.useRef(null); + const [lines, setLines] = useState>([]); + + // connectRoom: reusable connect logic for initial attempt and retries + const connectRoom = React.useCallback( + async (attemptToken?: string, attemptServer?: string) => { + if (connectingRef.current) return; + connectingRef.current = true; + setConnectError(null); + try { + const sUrl = attemptServer || serverUrl; + const tk = attemptToken || token; + if (!sUrl || !tk) { + // Avoid throwing inside this catch-all to keep analyzer happy; set error and return + setConnectError('Missing serverUrl or token'); + return; + } + // Only call connect if this component owns the room (internal) + if (!isExternalRoom && (room as Room).connect) { + await (room as Room).connect(sUrl, tk); + } + connectedRef.current = true; + setConnectError(null); + onConnected?.(); + } catch (err: any) { + console.error('StudioRoom connect failed', err); + setConnectError(String(err?.message || err || 'Connection failed')); + } finally { + connectingRef.current = false; + } + }, + [/* room purposely omitted to avoid re-creating callback */, serverUrl, token, onConnected, isExternalRoom] ); useEffect(() => { let mounted = true; - const connect = async () => { - if (mounted) { - await room.connect(serverUrl, token); + // Attempt initial connect once when mounted + (async () => { + if (!mounted) return; + // If we're using an internal room, attempt initial connect + if (!isExternalRoom) await connectRoom(); + else { + // If external room is already connected, notify parent + try { if ((room as any)?.state === 'connected' || (room as any)?.isConnected) { connectedRef.current = true; onConnected?.(); } } catch(e){} + } + })(); + + // If token or serverUrl changes after mount, attempt to connect (useful when token is injected later) + // No polling here: connection will be attempted on mount, and further + // attempts are triggered by an effect that watches `token`/`serverUrl`. + return () => { + mounted = false; + try { (room as any).off && (room as any).off('dataReceived', onDataReceived); } catch(e){} + try { if (onAcceptReceived) { (room as any).off && (room as any).off('dataReceived', onAcceptReceived as any); } } catch(e){} + try { + // Only disconnect if we actually connected + if (!isExternalRoom && connectedRef.current && room.disconnect) { + (room as Room).disconnect(); + } + } catch (e) { /* ignore */ } + onDisconnected?.(); + // poll removed + }; + }, [room, connectRoom, onDisconnected]); + + // Reactively attempt to connect whenever token or serverUrl changes + useEffect(() => { + try { + if (connectedRef.current) return; // already connected + if (!connectingRef.current && (token && token.trim()) && (serverUrl && serverUrl.trim())) { + // attempt connection with the latest props + connectRoom(token, serverUrl); + } + } catch (e) { console.warn('reactive connect attempt failed', e); } + }, [token, serverUrl, connectRoom]); + + // Notify parent when the room actually becomes connected + useEffect(() => { + // Poll connectedRef to know when it's set by connectRoom + const t = setInterval(() => { + if (connectedRef.current) { onConnected?.(); + clearInterval(t); + } + }, 250); + return () => clearInterval(t); + }, [onConnected]); + + // If using external room, notify parent when it becomes connected + useEffect(() => { + if (!isExternalRoom) return; + const checkInterval = setInterval(() => { + try { + if ((room as any)?.state === 'connected' || (room as any)?.isConnected) { + connectedRef.current = true; + onConnected?.(); + clearInterval(checkInterval); + } + } catch(e){} + }, 250); + return () => clearInterval(checkInterval); + }, [isExternalRoom, room, onConnected]); + + // Auto-start camera, mic, and "recording" when connected + useEffect(() => { + if (!connectedRef.current) return; + + const autoStart = async () => { + try { + const lp = room.localParticipant; + if (!lp) return; + + // Auto-enable camera + try { + await lp.setCameraEnabled(true); + console.log('Auto-enabled camera'); + } catch (e) { + console.warn('Failed to auto-enable camera:', e); + } + + // Auto-enable microphone + try { + await lp.setMicrophoneEnabled(true); + console.log('Auto-enabled microphone'); + } catch (e) { + console.warn('Failed to auto-enable microphone:', e); + } + + // NOTE: removed automatic recording/start signal per request (focus on transmission only) + + } catch (e) { + console.warn('Auto-start failed:', e); } }; - connect(); + // Small delay to ensure room is fully ready + const timer = setTimeout(autoStart, 1000); + return () => clearTimeout(timer); + }, [room]); + + useEffect(() => { + // layout change listener: apply data-layout attribute to root element + function onLayoutChange(e: any) { + try { + const layoutId = e?.detail?.layoutId; + const root = document.querySelector('.studio-room'); + if (root && layoutId) { + (root as HTMLElement).setAttribute('data-layout', String(layoutId)); + console.log('Applied layout', layoutId); + } + } catch (err) { console.warn('layout change handler error', err) } + } + window.addEventListener('avz:layout:change', onLayoutChange as EventListener); return () => { - mounted = false; - room.disconnect(); - onDisconnected?.(); + window.removeEventListener('avz:layout:change', onLayoutChange as EventListener); }; - }, [room, serverUrl, token, onConnected, onDisconnected]); + }, []); + + // Recalculate overlay lines between moderator (local) and guests + React.useEffect(() => { + function computeLines(){ + try{ + const container = previewRef.current; + if (!container) return setLines([]); + const rootRect = container.getBoundingClientRect(); + // find moderator tile by identity + const localIdentity = room.localParticipant?.identity; + let moderatorEl: Element | null = null; + if (localIdentity) { + moderatorEl = Array.from(container.querySelectorAll('.lk-participant-name')).find(el => (el.textContent || '').trim() === localIdentity) as Element || null; + } + // fallback: try first participant tile inside container + if (!moderatorEl) moderatorEl = container.querySelector('.lk-participant-tile'); + + if (!moderatorEl) return setLines([]); + const mRect = (moderatorEl as HTMLElement).getBoundingClientRect(); + const mx = mRect.left + mRect.width/2 - rootRect.left; + const my = mRect.top + mRect.height/2 - rootRect.top; + + const newLines: Array<{x1:number,y1:number,x2:number,y2:number, accepted?: boolean}> = []; + // for each participant (excluding local), find tile by name and create line + participantsList.forEach(p => { + if (p.isLocal) return; + const el = Array.from(container.querySelectorAll('.lk-participant-name')).find(el => (el.textContent||'').trim() === p.identity) as Element | undefined; + if (!el) return; + const tRect = (el as HTMLElement).closest('.lk-participant-tile')?.getBoundingClientRect(); + if (!tRect) return; + const tx = tRect.left + tRect.width/2 - rootRect.left; + const ty = tRect.top + tRect.height/2 - rootRect.top; + newLines.push({ x1: mx, y1: my, x2: tx, y2: ty, accepted: !!p.accepted }); + }); + setLines(newLines); + }catch(e){ console.warn('computeLines error', e); setLines([]) } + } + computeLines(); + const ro = new ResizeObserver(()=> computeLines()); + if (previewRef.current) ro.observe(previewRef.current); + window.addEventListener('resize', computeLines); + const interval = setInterval(computeLines, 1200); + return ()=>{ ro.disconnect(); window.removeEventListener('resize', computeLines); clearInterval(interval); }; + }, [participantsList, room]); + + return (
+ {connectError && ( +
+
Error al conectar a LiveKit
+
{connectError}
+
Server: {serverUrl}
+
+ + +
+
+ )}
@@ -82,13 +283,24 @@ export const StudioRoom: React.FC = ({
- +
+ + {/* SVG overlay for connection lines */} + + {lines.map((ln,i)=>( + + ))} + +
+ {/* Our BottomControls will consume RoomContext and control mic/cam/recording */} + +
diff --git a/packages/studio-panel/src/main.tsx b/packages/studio-panel/src/main.tsx index 0a6034e..e9fd6ec 100644 --- a/packages/studio-panel/src/main.tsx +++ b/packages/studio-panel/src/main.tsx @@ -1,14 +1,105 @@ +import './styles/globals.css'; +import './styles.css'; + import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; -import 'avanza-ui/dist/studio-theme.css'; // Importar estilos del tema -const rootElement = document.getElementById('root'); -if (!rootElement) throw new Error('Failed to find the root element'); +(async function bootstrap() { + const skipProblematic = Boolean(import.meta.env.VITE_DEBUG_SKIP_PROB_IMPORTS); -ReactDOM.createRoot(rootElement).render( - - - -); + // Robust fallback: try to ensure studio-theme.css is present by adding a link tag resolved against this module + try { + const themeUrl = new URL('../../avanza-ui/src/styles/studio-theme.css', import.meta.url).toString(); + // only add if not already present + if (!document.querySelector(`link[href="${themeUrl}"]`)) { + const l = document.createElement('link'); + l.rel = 'stylesheet'; + l.href = themeUrl; + l.crossOrigin = 'anonymous'; + document.head.appendChild(l); + } + } catch (e) { + console.warn('Could not add link fallback for studio-theme.css:', (e as any)?.message || String(e)); + } + if (!skipProblematic) { + // Try to import shared styles (may fail if missing dependencies) + // NOTE: Importing broadcast-panel styles brings `@tailwind` directives which force PostCSS + // to load tailwind plugin. We only import it when explicitly requested via env var. + const importBroadcast = Boolean(import.meta.env.VITE_IMPORT_BROADCAST_STYLES); + if (importBroadcast) { + try { + await import('../../broadcast-panel/src/styles.css'); + } catch (e) { + console.warn('Failed to import broadcast-panel styles:', (e as any)?.message || String(e)); + } + } + + try { + await import('@livekit/components-styles'); + } catch (e) { + console.warn('Failed to import @livekit/components-styles:', (e as any)?.message || String(e)); + } + } + + const rootElement = document.getElementById('root'); + if (!rootElement) throw new Error('Failed to find the root element'); + + ReactDOM.createRoot(rootElement).render( + + + + ); +})(); + +// Small postMessage handshake helper so the SPA can interoperate with post_token_to_studio.html +// - respond to LIVEKIT_PING with LIVEKIT_READY +// - accept LIVEKIT_TOKEN and store it on window, then respond with LIVEKIT_ACK +(function setupPostMessageHandshake(){ + try { + // ensure we only add once + if ((window as any).__AVZ_POSTMESSAGE_SETUP) return; + (window as any).__AVZ_POSTMESSAGE_SETUP = true; + + // If token present in query params, expose immediately for app to pick up + try { + const p = new URLSearchParams(window.location.search); + const qtoken = p.get('token'); + const qroom = p.get('room') || ''; + const quser = p.get('username') || ''; + const qurl = p.get('serverUrl') || p.get('serverurl') || ''; + if (qtoken) { + (window as any).__AVANZACAST_PENDING_TOKEN = { token: qtoken, room: qroom, username: quser, url: qurl }; + try { window.dispatchEvent(new CustomEvent('avz:livekit:token', { detail: (window as any).__AVANZACAST_PENDING_TOKEN })); } catch(e){} + } + } catch(e) {} + + window.addEventListener('message', (e: MessageEvent) => { + try { + const d = e.data || {}; + if (d && typeof d === 'object') { + // ping -> ready + if (d.type === 'LIVEKIT_PING') { + try { (e.source as any)?.postMessage?.({ type: 'LIVEKIT_READY' }, e.origin || '*'); } catch (err) {} + return; + } + // token received -> store and ack + if (d.type === 'LIVEKIT_TOKEN') { + try { + // store pending token for the app to pick up + (window as any).__AVANZACAST_PENDING_TOKEN = { token: d.token, room: d.room, username: d.username, url: d.url }; + // also store the source/origin so the App can ACK directly to it + try { (window as any).__AVZ_LAST_MSG_SOURCE = { origin: e.origin || null, source: e.source || null }; } catch (err) { (window as any).__AVZ_LAST_MSG_SOURCE = null; } + } catch(e){} + // Do NOT send a postMessage ACK here. ACKs are centralized in the React App + // to avoid duplicated acknowledgements back to the sender. The App will listen + // for the 'avz:livekit:token' event and send any required ACK. + try { window.dispatchEvent(new CustomEvent('avz:livekit:token', { detail: (window as any).__AVANZACAST_PENDING_TOKEN })); } catch(e){} + return; + } + } + } catch (err) { /* ignore */ } + }, false); + } catch (err) { /* ignore */ } +})(); diff --git a/packages/studio-panel/src/styles.css b/packages/studio-panel/src/styles.css index 8ae417b..d49db86 100644 --- a/packages/studio-panel/src/styles.css +++ b/packages/studio-panel/src/styles.css @@ -1,6 +1,8 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import './styles/avanza-utilities.css'; + +/* Import avanza-ui theme (standalone CSS in packages/avanza-ui) */ +@import '../../avanza-ui/src/styles/globals.css'; +@import '../../avanza-ui/src/styles/studio-theme.css'; /* small design tokens to match AvanzaCast palette */ :root{ @@ -10,4 +12,3 @@ .bg-surface-50{ background-color: var(--surface-50); } .dark .bg-surface-900{ background-color: var(--surface-900); } - diff --git a/packages/studio-panel/src/styles/avanza-utilities.css b/packages/studio-panel/src/styles/avanza-utilities.css new file mode 100644 index 0000000..0a8f9c4 --- /dev/null +++ b/packages/studio-panel/src/styles/avanza-utilities.css @@ -0,0 +1,272 @@ +/* avanza-utilities.css + Minimal utility set that mimics the Tailwind classes used in studio-panel. + This lets studio-panel avoid depending on Tailwind at runtime while keeping a + similar look-and-feel compatible with avanza-ui styles. +*/ + +:root{ + --gap-3: 0.75rem; /* 12px */ + --p-2: 0.5rem; /* 8px */ + --px-4: 1rem; /* 16px */ + --py-3: 0.75rem; /* 12px */ + --rounded-md: 0.5rem; /* 8px - slightly larger */ + --rounded-full: 9999px; + --w-10: 2.5rem; /* 40px */ + --h-10: 2.5rem; + --w-12: 3rem; /* 48px */ + --h-12: 3rem; + --bg-black-70: rgba(0,0,0,0.7); + --bg-white-10: rgba(255,255,255,0.08); + --text-gray-400: #9ca3af; + --bg-red-600: #e11d48; /* slightly brighter */ + --text-white: #ffffff; + + /* streamyard-like tokens */ + --studio-control-size: 44px; + --studio-control-gap: 12px; + --studio-shadow: 0 6px 18px rgba(15,23,42,0.12); +} + +/* layout */ +.flex{display:flex} +.flex-col{flex-direction:column} +.items-center{align-items:center} +.justify-center{justify-content:center} +.gap-3{gap:var(--gap-3)} + +/* spacing */ +.p-2{padding:var(--p-2)} +.px-4{padding-left:var(--px-4);padding-right:var(--px-4)} +.py-3{padding-top:var(--py-3);padding-bottom:var(--py-3)} + +/* sizes */ +.w-10{width:var(--w-10)} +.h-10{height:var(--h-10)} +.w-12{width:var(--w-12)} +.h-12{height:var(--h-12)} +.flex-1{flex:1 1 0} + +/* rounded */ +.rounded-md{border-radius:var(--rounded-md)} +.rounded-full{border-radius:var(--rounded-full)} + +/* text */ +.font-semibold{font-weight:600} +.font-medium{font-weight:500} +.text-xs{font-size:0.75rem} +.text-gray-400{color:var(--text-gray-400)} +.mb-3{margin-bottom:0.75rem} + +/* spacing helpers used by bottom control */ +.fixed{position:fixed} +.bottom-4{bottom:1rem} +.left-4{left:1rem} +.right-4{right:1rem} + +/* background helpers - we must handle classes that contain slashes (e.g. bg-black/70) + using attribute selectors so we don't need to change component markup. +*/ +[class~="bg-black/70"]{background-color:var(--bg-black-70)} +[class~="bg-white/10"]{background-color:var(--bg-white-10)} + +/* surface tokens - these mirror variables used across project */ +.bg-surface-50{background-color:var(--surface-50)} +.dark .bg-surface-900{background-color:var(--surface-900)} + +/* specific colors */ +.bg-red-600{background-color:var(--bg-red-600)} +.text-white{color:var(--text-white)} + +/* utilities for lists and spacing */ +.space-y-3 > * + *{margin-top:var(--gap-3)} + +/* small card/video grid helpers */ +.video-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px} + +/* lower-third and studio specific helpers */ +.lower-third{background:linear-gradient(90deg, rgba(0,0,0,0.65), rgba(0,0,0,0.55));color:white;padding:10px;border-radius:8px;box-shadow:var(--studio-shadow)} +.lower-third-title{font-weight:600} +.lower-third-subtitle{font-size:0.85rem;opacity:0.9} + +/* debug helpers */ +.bg-debug{outline:1px dashed rgba(0,0,0,0.08)} + +/* ensure buttons visually match Tailwind defaults used in components */ +button{font-family:inherit} + +/* control buttons */ +.btn-control{ + width:var(--studio-control-size); + height:var(--studio-control-size); + border-radius:9999px; + display:inline-flex; + align-items:center; + justify-content:center; + background:var(--bg-white-10, rgba(255,255,255,0.08)); + color:var(--text-white); + border:1px solid rgba(255,255,255,0.04); + transition: transform 120ms ease, background 120ms ease, box-shadow 120ms ease, opacity 120ms ease; + cursor:pointer; +} + +.btn-control:hover{ + transform: translateY(-3px); + box-shadow: var(--studio-shadow, 0 6px 18px rgba(15,23,42,0.12)); +} + +.btn-control:active{ + transform: translateY(0); +} + +.btn-control:focus{ + outline: 2px solid rgba(79,70,229,0.24); + outline-offset: 3px; +} + +.btn-control[aria-pressed="true"]{ + opacity:0.95; + transform: scale(0.98); +} + +.btn-control--danger{ + background: var(--studio-recording, #ef4444); + color: var(--text-white); + border-color: rgba(0,0,0,0.12); +} + +.btn-control--danger:hover{ transform: translateY(-3px) scale(1.02); } + +/* recording dot */ +.btn-control--danger .record-dot{ + position:absolute; + top:-6px; + right:-6px; + width:12px; + height:12px; + border-radius:50%; + background: var(--studio-recording, #ef4444); + box-shadow: 0 2px 8px rgba(225,29,72,0.45); + animation: pulse-record 1.1s infinite ease-in-out; +} + +@keyframes pulse-record{ + 0%{ transform: scale(1); opacity:1 } + 50%{ transform: scale(1.5); opacity:0.5 } + 100%{ transform: scale(1); opacity:1 } +} + +/* Tooltip using data-tooltip attr */ +[data-tooltip]{ position: relative; } +[data-tooltip]::after{ + content: attr(data-tooltip); + position: absolute; + bottom: calc(100% + 10px); + left: 50%; + transform: translateX(-50%) translateY(6px); + background: rgba(20,20,20,0.9); + color:white; + padding:6px 8px; + border-radius:6px; + font-size:12px; + white-space:nowrap; + opacity:0; + pointer-events:none; + transition: opacity 120ms ease, transform 120ms ease; + z-index:9999; +} +[data-tooltip]:hover::after, +[data-tooltip]:focus::after{ + opacity:1; + transform: translateX(-50%) translateY(0); +} + +/* Accessible tooltip element (used with aria-describedby). Placed next to .btn-control */ +.control-wrapper{ position: relative; display:inline-flex; align-items:center; } +.tooltip{ + position: absolute; + bottom: calc(100% + 10px); + left: 50%; + transform: translateX(-50%) translateY(6px); + background: rgba(20,20,20,0.95); + color: #fff; + padding:6px 10px; + border-radius:8px; + font-size:12px; + white-space:nowrap; + opacity:0; + pointer-events:none; + transition: opacity 140ms ease, transform 140ms ease; + z-index:9999; + box-shadow: 0 6px 18px rgba(2,6,23,0.35); +} + +/* Show tooltip when the previous button is hovered or focused (keyboard) */ +.control-wrapper:focus-within .tooltip, +.control-wrapper:hover .tooltip{ + opacity:1; + transform: translateX(-50%) translateY(0); + pointer-events:auto; +} + +/* Visually-hidden helper for screen readers */ +.visually-hidden{ + position: absolute !important; + height: 1px; width: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); + white-space: nowrap; /* added line */ +} + +/* Disabled state for controls */ +.btn-control[disabled]{ + opacity:0.45; + cursor:not-allowed; + transform:none; + pointer-events:none; +} + +/* Focus-visible (more explicit keyboard focus) */ +.btn-control:focus-visible{ + outline: 3px solid rgba(79,70,229,0.22); + outline-offset: 4px; +} + +/* Respect user motion preferences */ +@media (prefers-reduced-motion: reduce){ + .btn-control, + .btn-control:hover, + .btn-control:active, + .btn-control:focus{ + transition: none !important; + transform: none !important; + animation: none !important; + } + .tooltip{ transition: none !important } +} + +/* positioning helper for container to allow absolute children */ +.controls-inner{ position: relative; display:flex; align-items:center } + +/* Improve recording visuals: ring behind the button and stronger dot pulse */ +.btn-control{ position: relative; z-index: 1; } + +.btn-control.recording::after{ + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%) scale(0.9); + width: calc(var(--studio-control-size) + 18px); + height: calc(var(--studio-control-size) + 18px); + border-radius: 9999px; + background: rgba(239,68,68,0.12); + z-index: 0; + pointer-events: none; + animation: ring-record 1600ms ease-out infinite; +} + +@keyframes ring-record{ + 0%{ transform: translate(-50%, -50%) scale(0.9); opacity: 0.9 } + 60%{ transform: translate(-50%, -50%) scale(1.4); opacity: 0.14 } + 100%{ transform: translate(-50%, -50%) scale(1.6); opacity: 0 } +} diff --git a/packages/studio-panel/src/utils/postMessage.ts b/packages/studio-panel/src/utils/postMessage.ts new file mode 100644 index 0000000..c10cd24 --- /dev/null +++ b/packages/studio-panel/src/utils/postMessage.ts @@ -0,0 +1,39 @@ +// Utilities for postMessage origin validation and ACK helpers +export function getAllowedOriginsFromEnv(): string[] { + const allowed = new Set(); + try { + const raw = (import.meta.env.VITE_STUDIO_ALLOWED_ORIGINS as string) || ''; + if (raw) { + raw.split(',').map(s => s.trim()).filter(Boolean).forEach(o => allowed.add(o)); + } + } catch (e) { /* ignore */ } + try { + const studioUrl = (import.meta.env.VITE_STUDIO_URL as string) || ''; + if (studioUrl) { + try { + const u = new URL(studioUrl); + allowed.add(u.origin); + } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore */ } + try { allowed.add(window.location.origin); } catch (e) {} + return Array.from(allowed); +} + +export function isAllowedOrigin(origin: string | null | undefined): boolean { + if (!origin) return false; + const list = getAllowedOriginsFromEnv(); + return list.includes(origin); +} + +export function safePostMessage(target: Window | null | undefined, message: any, targetOrigin: string) { + if (!target) return false; + try { + target.postMessage(message, targetOrigin); + return true; + } catch (e) { + // some window proxies can throw when cross-origin; ignore + return false; + } +} + diff --git a/packages/studio-panel/tests/e2e/session_flow.spec.ts b/packages/studio-panel/tests/e2e/session_flow.spec.ts new file mode 100644 index 0000000..98a2f1b --- /dev/null +++ b/packages/studio-panel/tests/e2e/session_flow.spec.ts @@ -0,0 +1,70 @@ +import { test, expect } from '@playwright/test'; + +// Production domains (override with env vars if needed) +const BROADCAST_URL = process.env.BROADCAST_URL || 'https://avanzacast-broadcastpanel.bfzqqk.easypanel.host/post_token_to_studio.html?auto=1'; +const STUDIO_ORIGIN = process.env.STUDIO_ORIGIN || 'https://avanzacast-studio.bfzqqk.easypanel.host'; +const TOKEN_SERVER = process.env.TOKEN_SERVER_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host'; + +test('broadcast -> token -> studio flow (production domains)', async ({ browser }) => { + const context = await browser.newContext({ ignoreHTTPSErrors: true }); + const page = await context.newPage(); + + // Navigate to broadcast simulator / page that triggers token creation + await page.goto(BROADCAST_URL, { waitUntil: 'networkidle' }); + + // Try to trigger flow: either the page auto-runs (auto=1), opens a popup, or requires a click + // Wait for a new page with studio origin (popup) for up to 12s + let studioPage = null as (import('@playwright/test').Page | null); + try { + const popupPromise = context.waitForEvent('page', { timeout: 12000 }); + + // If there's a visible button, click it (best-effort) + const openButton = page.locator('text=Open Studio and Send Token, text=Entrar al estudio, text=Open Studio'); + if (await openButton.count() > 0) { + try { await openButton.first().click({ timeout: 3000 }); } catch (_) { /* ignore */ } + } + + // Wait for popup + studioPage = await popupPromise; + } catch (e) { + // popup not opened — maybe the page redirected the same tab + } + + // If the broadcast redirected the current page to studio origin + if (!studioPage && page.url().startsWith(STUDIO_ORIGIN)) { + studioPage = page; + } + + // Fallback: request a session from token server and open the redirectUrl directly + if (!studioPage) { + try { + const resp = await page.request.post(`${TOKEN_SERVER}/api/session`, { + data: { room: 'studio-demo', username: 'playwright-e2e' }, + timeout: 15000, + }); + const json = await resp.json(); + const redirectUrl = json?.redirectUrl; + if (redirectUrl) { + studioPage = await context.newPage(); + await studioPage.goto(redirectUrl, { waitUntil: 'networkidle' }); + } + } catch (err) { + // ignore — we'll assert later + } + } + + expect(studioPage, 'Studio page should be opened (popup or redirect or fallback)') + .not.toBeNull(); + + // Wait for receiver status element and assert token received + const status = studioPage!.locator('#status'); + await expect(status).toBeVisible({ timeout: 10000 }); + const txt = await status.innerText(); + expect(txt).toMatch(/Token recibido|Token recibido \(query\)|Token received/i); + + // Save screenshot for debugging / CI + await studioPage!.screenshot({ path: '/tmp/e2e_studio_received.png', fullPage: true }); + + await context.close(); +}); + diff --git a/packages/studio-panel/vite.config.ts b/packages/studio-panel/vite.config.ts index 34c8862..ae5c12c 100644 --- a/packages/studio-panel/vite.config.ts +++ b/packages/studio-panel/vite.config.ts @@ -2,6 +2,16 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'path'; +// Derive HMR host from environment if available (VITE_STUDIO_URL set in broadcast-panel .env) +const studioUrl = process.env.VITE_STUDIO_URL || process.env.STUDIO_URL || 'https://avanzacast-studio.bfzqqk.easypanel.host' +let hmrHost = 'avanzacast-studio.bfzqqk.easypanel.host' +try { + const u = new URL(studioUrl) + hmrHost = u.hostname +} catch (e) { + // ignore, fallback kept +} + export default defineConfig({ plugins: [react()], resolve: { @@ -10,8 +20,17 @@ export default defineConfig({ }, }, server: { - port: 3001, + host: '0.0.0.0', // allow access from network / external proxy + port: 3020, strictPort: false, + hmr: { + protocol: 'wss', + host: hmrHost, + clientPort: 443, + }, + }, + preview: { + host: '0.0.0.0', + port: 3020, }, }); - diff --git a/packages/studio-panel/vitest.config.ts b/packages/studio-panel/vitest.config.ts new file mode 100644 index 0000000..5fdceea --- /dev/null +++ b/packages/studio-panel/vitest.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config' +import path from 'path' + +export default defineConfig({ + resolve: { + alias: { + 'avanza-ui': path.resolve(__dirname, '../avanza-ui/src'), + }, + }, + test: { + environment: 'jsdom', + globals: true, + setupFiles: ['./src/setupTests.ts'], + include: ['src/**/*.test.{ts,tsx}', 'src/**/__tests__/**/*.ts', 'src/**/__tests__/**/*.tsx'] + } +}) diff --git a/scripts/check_cors.sh b/scripts/check_cors.sh new file mode 100755 index 0000000..b716b95 --- /dev/null +++ b/scripts/check_cors.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +OUT_DIR=".deploy_out" +mkdir -p "$OUT_DIR" +TS=$(date +%s) +OUT="${OUT_DIR}/cors_check_${TS}.log" + +echo "Starting CORS check - output -> $OUT" +exec &> >(tee "$OUT") + +BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)" +cd "$BASE_DIR/packages/backend-api" + +# stop previous backend if recorded +if [ -f /tmp/backend_api_pid.txt ]; then + PID=$(cat /tmp/backend_api_pid.txt) || true + if [ -n "$PID" ] && ps -p "$PID" > /dev/null 2>&1; then + echo "Stopping previous backend (pid=$PID)" + kill "$PID" || kill -9 "$PID" || true + sleep 1 + fi + rm -f /tmp/backend_api_pid.txt +fi + +# move old logs +[ -f /tmp/backend_api_run.log ] && mv /tmp/backend_api_run.log /tmp/backend_api_run.log.bak || true + +# source .env.production if exists (do not leak secrets) +if [ -f ./.env.production ]; then + echo "Sourcing ./.env.production" + set -a + # shellcheck disable=SC1090 + . ./.env.production + set +a +else + echo "No ./.env.production found in packages/backend-api — ensure env vars are set if needed" +fi + +# Start backend with ALLOW_ALL_CORS=1 for debugging (background) +echo "Starting backend with ALLOW_ALL_CORS=1 (debug mode)" +nohup env ALLOW_ALL_CORS=1 npx tsx src/index.ts > /tmp/backend_api_run.log 2>&1 & +echo $! > /tmp/backend_api_pid.txt +sleep 2 + +echo "--- /tmp/backend_api_run.log (head) ---" +head -n 200 /tmp/backend_api_run.log || true + +BROADCAST_ORIGIN="https://avanzacast-broadcastpanel.bfzqqk.easypanel.host" +TOKEN_URL="http://localhost:4000/api/token?room=studio-demo&username=simulator" + +echo "--- Curl test against $TOKEN_URL with Origin: $BROADCAST_ORIGIN ---" +curl -i -s -H "Origin: $BROADCAST_ORIGIN" "$TOKEN_URL" | sed -n '1,200p' || true + +echo "\n--- backend log (tail) ---" +tail -n 200 /tmp/backend_api_run.log || true + +# show PID info +if [ -f /tmp/backend_api_pid.txt ]; then + echo "Backend PID: $(cat /tmp/backend_api_pid.txt)" + ps -p $(cat /tmp/backend_api_pid.txt) -o pid,ppid,cmd || true +fi + +# show listening sockets +echo "\n--- Listening sockets for :4000 ---" +ss -ltnp | rg 4000 || true + +cat "$OUT" + +echo "CORS check finished. Log saved at $OUT" + diff --git a/scripts/restart_backend_prod.sh b/scripts/restart_backend_prod.sh new file mode 100755 index 0000000..06a8565 --- /dev/null +++ b/scripts/restart_backend_prod.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +# restart_backend_prod.sh +# Usage: +# Run this on the production host where the repository is deployed. +# ./restart_backend_prod.sh [mode] +# Modes: +# docker - use docker compose to recreate backend-api (default) +# node - restart node process started with npx tsx +# systemd - restart systemd service named backend-api +# +MODE=${1:-docker} +COMPOSE_FILE=${COMPOSE_FILE:-/home/xesar/Documentos/Nextream/AvanzaCast/docker-compose.prod.yml} +REPO_DIR=${REPO_DIR:-/home/xesar/Documentos/Nextream/AvanzaCast} + +echo "--> Restart backend-api (mode=$MODE)" + +if [ "$MODE" = "docker" ]; then + echo "Using docker-compose file: $COMPOSE_FILE" + if ! command -v docker >/dev/null 2>&1; then + echo "Docker not found on PATH; cannot continue in docker mode" >&2 + exit 2 + fi + cd "$(dirname "$COMPOSE_FILE")" || cd "$REPO_DIR" || true + echo "Recreating backend-api service (no deps, force recreate)" + docker compose -f "$COMPOSE_FILE" up -d --no-deps --force-recreate backend-api + echo "Waiting 3s for startup..." + sleep 3 + echo "--- docker compose ps backend-api ---" + docker compose -f "$COMPOSE_FILE" ps backend-api || true + echo "--- docker ps (filter backend-api) ---" + docker ps --filter name=backend-api || true + echo "--- backend-api logs (last 200 lines) ---" + docker compose -f "$COMPOSE_FILE" logs --tail=200 backend-api || true +elif [ "$MODE" = "node" ]; then + echo "Restarting node process (npx tsx)..." + # This assumes the process was started with a matching pattern + pkill -f 'npx tsx src/index.ts' || true + sleep 1 + cd "$REPO_DIR/packages/backend-api" || true + # Start in background (modify as needed for your env) + nohup npx tsx src/index.ts > /tmp/backend_api_run.log 2>&1 & + echo $! > /tmp/backend_api_pid.txt + sleep 2 + tail -n 200 /tmp/backend_api_run.log || true +elif [ "$MODE" = "systemd" ]; then + echo "Restarting systemd service: backend-api" + sudo systemctl restart backend-api.service + sudo journalctl -u backend-api.service -n 200 --no-pager || true +else + echo "Unknown mode: $MODE" >&2 + exit 3 +fi + +# Basic health checks (local) +echo "\n--- Local health check: http://localhost:4000/health ---" +if command -v curl >/dev/null 2>&1; then + curl -sS http://localhost:4000/health || echo "Local health check failed or endpoint not reachable" +else + echo "curl not available to run health check" +fi + +echo "\n--- CORS quick check (OPTIONS against production token-server) ---" +PROD_HOST=${PROD_HOST:-https://avanzacast-servertokens.bfzqqk.easypanel.host} +if command -v curl >/dev/null 2>&1; then + curl -i -X OPTIONS "$PROD_HOST/api/session" \ + -H 'Origin: https://avanzacast-broadcastpanel.bfzqqk.easypanel.host' \ + -H 'Access-Control-Request-Method: POST' | sed -n '1,200p' +else + echo "curl not available to run CORS check" +fi + +cat <<'EOF' + +Done. If you ran this on the production host, please verify: +- The /health endpoint responds 200 +- The OPTIONS call returns Access-Control-Allow-Origin header for the broadcast domain +- A test POST to /api/session returns JSON with redirectUrl + +To revert a temporary ALLOW_ALL_CORS=1 deployment, restart the service without that env var, and ensure FRONTEND_URLS is set in the production environment. +EOF + diff --git a/scripts/smoke_studio_session.sh b/scripts/smoke_studio_session.sh new file mode 100755 index 0000000..64c5e7b --- /dev/null +++ b/scripts/smoke_studio_session.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Smoke test: crea una sesión en backend-api y abre el studio URL en el navegador (Linux: xdg-open) +# Usage: ./scripts/smoke_studio_session.sh [username] + +set -euo pipefail +ROOM=${1:-smoke-test} +USERNAME=${2:-smoke-user} +BACKEND=${BACKEND_API:-http://localhost:4000} + +echo "Creating session for room=$ROOM username=$USERNAME via ${BACKEND}/api/session" +resp=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"room\": \"${ROOM}\", \"username\": \"${USERNAME}\"}" "${BACKEND}/api/session") +if [ -z "$resp" ]; then + echo "No response from backend" + exit 1 +fi + +echo "Response: $resp" +studioUrl=$(echo "$resp" | python3 -c "import sys, json; print(json.load(sys.stdin).get('studioUrl',''))") +if [ -z "$studioUrl" ]; then + echo "studioUrl not found in response" + exit 1 +fi + +echo "Opening studio URL: $studioUrl" +if command -v xdg-open >/dev/null 2>&1; then + xdg-open "$studioUrl" +elif command -v gnome-open >/dev/null 2>&1; then + gnome-open "$studioUrl" +else + echo "Open this URL in your browser: $studioUrl" +fi + +echo "Smoke test completed (manual verification required: studio should auto-fetch token and connect)." +