Social Annotations in the Atmosphere
15
fork

Configure Feed

Select the types of activity you want to include in your feed.

clean up

+1296 -1088
+8 -6
AGENTS.md
··· 9 9 pnpm dev # Start WXT dev server with hot reload 10 10 pnpm build # Build extension for production 11 11 pnpm zip # Package for Chrome/Firefox stores 12 - pnpm build:via # Build proxy client 13 - pnpm dev:via # Watch mode for proxy client 12 + pnpm build:proxy # Build proxy client (wabac.js) 13 + pnpm dev:proxy # Build and run proxy (http://127.0.0.1:8081) 14 14 pnpm build:landing # Build landing page 15 15 ``` 16 16 ··· 21 21 ├── entrypoints/ # Extension entry points (WXT) 22 22 │ ├── background.ts # Service worker 23 23 │ ├── content.ts # Content script 24 - │ ├── sidepanel/ # Sidebar UI 25 - │ └── via-client/ # Proxy sidebar client 24 + │ └── sidepanel/ # Sidebar UI 26 25 ├── packages/core/ # Shared core logic (@seams/core) 27 26 │ └── src/ 28 27 │ ├── background/ # Background worker logic ··· 33 32 │ ├── storage/ # Storage adapters 34 33 │ ├── utils/ # Utilities (highlights, selectors) 35 34 │ └── types.ts # TypeScript interfaces 35 + ├── proxy/ # Web proxy (wabac.js-based) 36 + │ ├── src/ # Proxy client scripts 37 + │ ├── cors-proxy/ # CORS proxy server 38 + │ └── html/ # HTML templates 36 39 ├── landing/ # Public landing page 37 - ├── proxy/ # pywb proxy service 38 40 └── history/ # Architecture docs and planning 39 41 ``` 40 42 ··· 190 192 ## Environment Variables 191 193 ```bash 192 194 BACKEND_URL=http://localhost:8080 # Extension - Production: https://seams.so 193 - VITE_OAUTH_CLIENT_ID=... # Via client OAuth 195 + VITE_OAUTH_CLIENT_ID=... # Proxy client OAuth 194 196 VITE_OAUTH_REDIRECT_URI=... 195 197 VITE_BACKEND_URL=... 196 198 ```
-51
Caddyfile
··· 1 - # Seams Via Proxy - Development Configuration 2 - # Use http:// to disable automatic HTTPS 3 - :8082 { 4 - bind 0.0.0.0 5 - # Proxy routes to pywb (must come first) 6 - handle /proxy/* { 7 - reverse_proxy 127.0.0.1:8081 { 8 - # Trust upstream headers for scheme/host 9 - header_up X-Forwarded-Proto {header.X-Forwarded-Proto} 10 - header_up X-Forwarded-Host {host} 11 - header_down -Content-Security-Policy 12 - } 13 - } 14 - 15 - # Proxy static files served by pywb 16 - handle /static/* { 17 - reverse_proxy 127.0.0.1:8081 18 - } 19 - 20 - # Redirect root to seams.so 21 - handle / { 22 - redir https://seams.so 23 - } 24 - 25 - # Serve .well-known for TWA (Digital Asset Links) 26 - handle /.well-known/* { 27 - root * proxy/static 28 - file_server 29 - } 30 - 31 - # OAuth callback rewrite 32 - handle /oauth/callback { 33 - root * proxy/static 34 - rewrite * /oauth-callback.html 35 - file_server 36 - } 37 - 38 - # Serve static files (CSS, JS, etc) from proxy/static 39 - handle /* { 40 - root * proxy/static 41 - try_files {path} {path}.html 42 - file_server 43 - } 44 - 45 - # Enable logging 46 - log { 47 - output stdout 48 - format console 49 - level INFO 50 - } 51 - }
+58 -48
Dockerfile.proxy
··· 1 - # Build stage - compile via client with Node 2 - FROM node:20-alpine AS builder 1 + # Dockerfile for Proxy (wabac.js-based) 2 + # Multi-stage build: Node.js for building, then slim runtime 3 + 4 + # Build stage - compile proxy with Node 5 + FROM node:22-alpine AS builder 3 6 4 7 RUN apk add --no-cache bash 5 8 RUN npm install -g pnpm 6 9 7 10 WORKDIR /build 11 + 12 + # Copy workspace config 8 13 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ 9 14 COPY packages/ ./packages/ 10 - COPY entrypoints/via-client/ ./entrypoints/via-client/ 11 - COPY entrypoints/sidepanel/ ./entrypoints/sidepanel/ 12 - COPY proxy/via-html/ ./proxy/via-html/ 13 - COPY landing/landing.css landing/fonts.css landing/favicon.ico ./landing/ 14 - COPY landing/fonts/ ./landing/fonts/ 15 - COPY landing/oauth/client-metadata.json ./landing/oauth/ 16 - COPY vite.via.config.ts tsconfig.json ./ 17 - COPY scripts/postbuild-via.sh ./scripts/ 15 + COPY proxy/ ./proxy/ 16 + COPY vite.proxy.config.ts vite.proxy-inject.config.ts vite.proxy.shared.ts tsconfig.json ./ 17 + COPY scripts/postbuild-proxy.sh ./scripts/ 18 18 19 + # Install dependencies 19 20 RUN pnpm install --frozen-lockfile 20 - RUN BACKEND_URL=https://seams.so pnpm build:via 21 21 22 - # Runtime stage 23 - FROM python:3.11-slim 22 + # Install proxy dependencies (for wabac.js sw.js) 23 + WORKDIR /build/proxy 24 + RUN npm install 25 + 26 + # Build proxy with HMAC secret from build-time secret 27 + # The secret is mounted at /run/secrets/CORS_PROXY_HMAC_SECRET during build 28 + WORKDIR /build 29 + RUN --mount=type=secret,id=CORS_PROXY_HMAC_SECRET \ 30 + VITE_CORS_PROXY_HMAC_SECRET=$(cat /run/secrets/CORS_PROXY_HMAC_SECRET 2>/dev/null || echo "") \ 31 + pnpm build:proxy 24 32 25 - # Install system dependencies 26 - RUN apt-get update && apt-get install -y --no-install-recommends \ 27 - curl \ 28 - ca-certificates \ 29 - && rm -rf /var/lib/apt/lists/* 33 + # Runtime stage - Node.js + Caddy 34 + FROM node:22-alpine 30 35 31 - # Install uv 32 - RUN curl -LsSf https://astral.sh/uv/install.sh | sh 33 - ENV PATH="/root/.local/bin:$PATH" 36 + RUN apk add --no-cache bash curl ca-certificates 34 37 35 38 # Install Caddy 36 - RUN curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64" -o /usr/local/bin/caddy \ 39 + RUN curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64&arm=" -o /usr/local/bin/caddy \ 37 40 && chmod +x /usr/local/bin/caddy 38 41 39 42 WORKDIR /app 40 43 41 - # Copy proxy config and collections 42 - COPY proxy/config.yaml ./proxy/ 43 - COPY proxy/collections/ ./proxy/collections/ 44 + # Copy built static files 45 + COPY --from=builder /build/proxy/dist/ ./dist/ 44 46 45 - # Copy built static files from builder 46 - COPY --from=builder /build/proxy/static/ ./proxy/static/ 47 + # Copy CORS proxy source and install dependencies 48 + COPY proxy/cors-proxy/ ./cors-proxy/ 49 + WORKDIR /app/cors-proxy 50 + RUN npm install 47 51 48 52 # Copy Caddyfile 49 - COPY Caddyfile ./ 53 + WORKDIR /app 54 + COPY proxy/Caddyfile ./ 50 55 51 56 # Create startup script 52 57 RUN cat <<'EOF' > /app/start.sh 53 58 #!/bin/bash 54 59 set -e 55 60 56 - echo "🚀 Starting Seams Proxy..." 61 + echo "Starting Seams Proxy..." 57 62 58 - # Install pywb at runtime using uv (like flake.nix does) 59 - echo "📦 Installing pywb..." 60 - export UV_CACHE_DIR=/root/.cache/uv 61 - export UV_TOOL_BIN_DIR=/root/.local/bin 62 - uv tool install pywb --with setuptools 63 + # Start CORS proxy on port 8083 (Caddy proxies 8082 -> 8083) 64 + cd /app/cors-proxy 65 + echo "Starting CORS proxy on :8083..." 66 + CORS_PROXY_PORT=8083 npx tsx index.ts & 67 + CORS_PID=$! 63 68 64 - # Add local bin to PATH 65 - export PATH=$PATH:/root/.local/bin 66 - 67 - # Start wayback (pywb) on port 8081 68 - cd /app/proxy 69 - echo "📦 Starting wayback on :8081" 70 - wayback -p 8081 -b 127.0.0.1 & 71 - WB_PID=$! 72 - 73 - # Wait for wayback to initialize 74 - sleep 2 69 + # Wait for CORS proxy to be healthy (up to 30 seconds) 70 + echo "Waiting for CORS proxy to be ready..." 71 + MAX_ATTEMPTS=30 72 + ATTEMPT=0 73 + while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do 74 + if curl -s -o /dev/null -w "%{http_code}" http://localhost:8083/ 2>/dev/null | grep -q "200"; then 75 + echo "CORS proxy is ready" 76 + break 77 + fi 78 + ATTEMPT=$((ATTEMPT + 1)) 79 + if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then 80 + echo "ERROR: CORS proxy failed to start within ${MAX_ATTEMPTS} seconds" 81 + exit 1 82 + fi 83 + sleep 1 84 + done 75 85 76 - # Start Caddy on port 8082 86 + # Start Caddy (static files on 8081, cors proxy on 8082) 77 87 cd /app 78 - echo "🌐 Starting Caddy on :8082" 88 + echo "Starting Caddy on :8081 (static) and :8082 (cors proxy)..." 79 89 caddy run --config /app/Caddyfile --adapter caddyfile 80 90 EOF 81 91 82 92 RUN chmod +x /app/start.sh 83 93 84 - EXPOSE 8082 94 + EXPOSE 8081 8082 85 95 86 96 CMD ["/app/start.sh"]
-98
Dockerfile.sure-client
··· 1 - # Dockerfile for Sure Client Proxy (wabac.js-based) 2 - # Multi-stage build: Node.js for building, then slim runtime 3 - 4 - # Build stage - compile sure-client with Node 5 - FROM node:22-alpine AS builder 6 - 7 - RUN apk add --no-cache bash 8 - RUN npm install -g pnpm 9 - 10 - WORKDIR /build 11 - 12 - # Copy workspace config 13 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ 14 - COPY packages/ ./packages/ 15 - COPY entrypoints/via-client/ ./entrypoints/via-client/ 16 - COPY entrypoints/sidepanel/ ./entrypoints/sidepanel/ 17 - COPY sure-client-proxy/ ./sure-client-proxy/ 18 - COPY vite.sure-client.config.ts vite.sure-client-inject.config.ts vite.sure-client.shared.ts tsconfig.json ./ 19 - COPY scripts/postbuild-sure-client.sh ./scripts/ 20 - 21 - # Install dependencies 22 - RUN pnpm install --frozen-lockfile 23 - 24 - # Install sure-client-proxy dependencies (for wabac.js sw.js) 25 - WORKDIR /build/sure-client-proxy 26 - RUN npm install 27 - 28 - # Build sure-client with HMAC secret from build-time secret 29 - # The secret is mounted at /run/secrets/CORS_PROXY_HMAC_SECRET during build 30 - WORKDIR /build 31 - RUN --mount=type=secret,id=CORS_PROXY_HMAC_SECRET \ 32 - VITE_CORS_PROXY_HMAC_SECRET=$(cat /run/secrets/CORS_PROXY_HMAC_SECRET 2>/dev/null || echo "") \ 33 - pnpm build:sure-client 34 - 35 - # Runtime stage - Node.js + Caddy 36 - FROM node:22-alpine 37 - 38 - RUN apk add --no-cache bash curl ca-certificates 39 - 40 - # Install Caddy 41 - RUN curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64&arm=" -o /usr/local/bin/caddy \ 42 - && chmod +x /usr/local/bin/caddy 43 - 44 - WORKDIR /app 45 - 46 - # Copy built static files 47 - COPY --from=builder /build/sure-client-proxy/dist/ ./dist/ 48 - 49 - # Copy CORS proxy source and install dependencies 50 - COPY sure-client-proxy/cors-proxy/ ./cors-proxy/ 51 - WORKDIR /app/cors-proxy 52 - RUN npm install 53 - 54 - # Copy Caddyfile 55 - WORKDIR /app 56 - COPY sure-client-proxy/Caddyfile ./ 57 - 58 - # Create startup script 59 - RUN cat <<'EOF' > /app/start.sh 60 - #!/bin/bash 61 - set -e 62 - 63 - echo "Starting Seams Sure Client Proxy..." 64 - 65 - # Start CORS proxy on port 8083 (Caddy proxies 8082 -> 8083) 66 - cd /app/cors-proxy 67 - echo "Starting CORS proxy on :8083..." 68 - CORS_PROXY_PORT=8083 npx tsx index.ts & 69 - CORS_PID=$! 70 - 71 - # Wait for CORS proxy to be healthy (up to 30 seconds) 72 - echo "Waiting for CORS proxy to be ready..." 73 - MAX_ATTEMPTS=30 74 - ATTEMPT=0 75 - while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do 76 - if curl -s -o /dev/null -w "%{http_code}" http://localhost:8083/ 2>/dev/null | grep -q "200"; then 77 - echo "CORS proxy is ready" 78 - break 79 - fi 80 - ATTEMPT=$((ATTEMPT + 1)) 81 - if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then 82 - echo "ERROR: CORS proxy failed to start within ${MAX_ATTEMPTS} seconds" 83 - exit 1 84 - fi 85 - sleep 1 86 - done 87 - 88 - # Start Caddy (static files on 8081, cors proxy on 8082) 89 - cd /app 90 - echo "Starting Caddy on :8081 (static) and :8082 (cors proxy)..." 91 - caddy run --config /app/Caddyfile --adapter caddyfile 92 - EOF 93 - 94 - RUN chmod +x /app/start.sh 95 - 96 - EXPOSE 8081 8082 97 - 98 - CMD ["/app/start.sh"]
+5 -4
README.md
··· 7 7 - **Browser Extension** (TypeScript/WXT) - Chrome/Firefox extension for creating and viewing annotations 8 8 - **Backend Server** (Go) - SQLite-backed indexing service for querying annotations by URL 9 9 - **Landing Page** (`landing/`) - Public feed of recent annotations 10 - - Proxy (`proxy/`) - Pure web based proxy to allow annotations 10 + - **Proxy** (`proxy/`) - Web-based proxy using wabac.js for annotation without extension 11 11 12 12 ## Quick Start 13 13 ··· 111 111 - chi (HTTP router) 112 112 113 113 **Proxy**: 114 - - `pywb` Server 115 - - Injects browser based sidebar and content script 116 - - Caddy wrapping 114 + - wabac.js (client-side service worker) 115 + - CORS proxy server (Node.js/Hono) 116 + - Injects browser-based sidebar and content script 117 + - Caddy for static files and reverse proxy 117 118 118 119 **Infrastructure**: 119 120 - Nix for reproducible development environments
+51 -29
deploy-proxy.sh
··· 1 - #!/usr/bin/env bash 1 + #!/bin/bash 2 + # Deploy Proxy to Fly.io 3 + # Usage: ./deploy-proxy.sh 4 + # 5 + # HMAC Authentication Setup: 6 + # 1. Create .env.secrets file (gitignored) with: CORS_PROXY_HMAC_SECRET=<your-secret> 7 + # 2. Or set environment variable: export CORS_PROXY_HMAC_SECRET=<your-secret> 8 + # 3. The script will set the Fly secret and use it for build 9 + # 10 + # Generate a secret with: openssl rand -base64 32 11 + 2 12 set -e 3 13 4 - # Define app name 5 14 APP_NAME="sure-seams-so" 6 - CONFIG_FILE="fly.proxy.toml" 7 - 8 - echo "Building proxy service" 9 - pnpm build:via 10 - 11 - echo "➕ Adding static assets to git index (for Nix)..." 12 - git add -f proxy/static 13 15 14 - echo "🏗️ Building Proxy Docker image with Nix..." 15 - nix build .#proxy 16 - 17 - echo "➖ Resetting git index..." 18 - git reset proxy/static 19 - 20 - echo "📦 Loading image into Docker..." 21 - docker load < result 22 - 23 - echo "🏷️ Tagging image for Fly.io registry..." 24 - docker tag seams-proxy:latest registry.fly.io/$APP_NAME:latest 25 - 26 - echo "🔐 Authenticating with Fly.io Docker registry..." 27 - flyctl auth docker 16 + echo "Deploying Proxy to Fly.io..." 28 17 29 - echo "⬆️ Pushing image to Fly.io..." 30 - docker push registry.fly.io/$APP_NAME:latest 18 + # Load secrets from .env.secrets if it exists 19 + if [ -f .env.secrets ]; then 20 + echo "Loading secrets from .env.secrets..." 21 + set -a 22 + source .env.secrets 23 + set +a 24 + fi 31 25 32 - echo "🚀 Deploying to Fly.io..." 33 - flyctl deploy --config $CONFIG_FILE --image registry.fly.io/$APP_NAME:latest 26 + # Check if HMAC secret is available 27 + if [ -n "$CORS_PROXY_HMAC_SECRET" ]; then 28 + echo "HMAC secret found, enabling authentication..." 29 + 30 + # Ensure the Fly.io app has the runtime secret 31 + echo "Setting runtime secret on Fly.io..." 32 + fly secrets set CORS_PROXY_HMAC_SECRET="$CORS_PROXY_HMAC_SECRET" --app "$APP_NAME" --stage 33 + 34 + # Deploy with build-time secret 35 + echo "Deploying with HMAC authentication..." 36 + fly deploy --config fly.proxy.toml \ 37 + --build-secret "CORS_PROXY_HMAC_SECRET=$CORS_PROXY_HMAC_SECRET" 38 + else 39 + echo "WARNING: CORS_PROXY_HMAC_SECRET not set" 40 + echo "HMAC authentication will be DISABLED" 41 + echo "" 42 + echo "To enable HMAC auth:" 43 + echo " 1. Generate secret: openssl rand -base64 32" 44 + echo " 2. Create .env.secrets with: CORS_PROXY_HMAC_SECRET=<secret>" 45 + echo " 3. Re-run this script" 46 + echo "" 47 + read -p "Continue without HMAC? (y/N) " -n 1 -r 48 + echo 49 + if [[ ! $REPLY =~ ^[Yy]$ ]]; then 50 + exit 1 51 + fi 52 + 53 + fly deploy --config fly.proxy.toml 54 + fi 34 55 35 - echo "✅ Proxy deployment complete!" 36 - echo "🌐 Visit: https://sure.seams.so" 56 + echo "" 57 + echo "Deployment complete!" 58 + echo "Visit: https://sure.seams.so"
-58
deploy-sure-client.sh
··· 1 - #!/bin/bash 2 - # Deploy Sure Client Proxy to Fly.io 3 - # Usage: ./deploy-sure-client.sh 4 - # 5 - # HMAC Authentication Setup: 6 - # 1. Create .env.secrets file (gitignored) with: CORS_PROXY_HMAC_SECRET=<your-secret> 7 - # 2. Or set environment variable: export CORS_PROXY_HMAC_SECRET=<your-secret> 8 - # 3. The script will set the Fly secret and use it for build 9 - # 10 - # Generate a secret with: openssl rand -base64 32 11 - 12 - set -e 13 - 14 - APP_NAME="sure-seams-so" 15 - 16 - echo "Deploying Sure Client Proxy to Fly.io..." 17 - 18 - # Load secrets from .env.secrets if it exists 19 - if [ -f .env.secrets ]; then 20 - echo "Loading secrets from .env.secrets..." 21 - set -a 22 - source .env.secrets 23 - set +a 24 - fi 25 - 26 - # Check if HMAC secret is available 27 - if [ -n "$CORS_PROXY_HMAC_SECRET" ]; then 28 - echo "HMAC secret found, enabling authentication..." 29 - 30 - # Ensure the Fly.io app has the runtime secret 31 - echo "Setting runtime secret on Fly.io..." 32 - fly secrets set CORS_PROXY_HMAC_SECRET="$CORS_PROXY_HMAC_SECRET" --app "$APP_NAME" --stage 33 - 34 - # Deploy with build-time secret 35 - echo "Deploying with HMAC authentication..." 36 - fly deploy --config fly.sure-client.toml \ 37 - --build-secret "CORS_PROXY_HMAC_SECRET=$CORS_PROXY_HMAC_SECRET" 38 - else 39 - echo "WARNING: CORS_PROXY_HMAC_SECRET not set" 40 - echo "HMAC authentication will be DISABLED" 41 - echo "" 42 - echo "To enable HMAC auth:" 43 - echo " 1. Generate secret: openssl rand -base64 32" 44 - echo " 2. Create .env.secrets with: CORS_PROXY_HMAC_SECRET=<secret>" 45 - echo " 3. Re-run this script" 46 - echo "" 47 - read -p "Continue without HMAC? (y/N) " -n 1 -r 48 - echo 49 - if [[ ! $REPLY =~ ^[Yy]$ ]]; then 50 - exit 1 51 - fi 52 - 53 - fly deploy --config fly.sure-client.toml 54 - fi 55 - 56 - echo "" 57 - echo "Deployment complete!" 58 - echo "Visit: https://sure.seams.so"
+8 -19
entrypoints/via-client/main.ts proxy/src/main.ts
··· 1 - // Via proxy client - handles page interaction and communicates with parent frame (shell) 1 + // Proxy client - handles page interaction and communicates with parent frame (shell) 2 2 // This runs inside the wabac.js proxied iframe which cannot access localStorage 3 3 // Uses PostMessageStorageAdapter to request data from shell 4 4 import { PostMessageStorageAdapter, ProxyContentScript, applyHighlights, clearHighlights, generateSelectors, isAllowedOrigin } from '@seams/core'; 5 5 6 - console.log('[seams-client] Seams via client loaded!'); 6 + console.log('[seams-client] Seams client loaded!'); 7 7 8 8 // Determine the shell origin from the parent frame 9 9 // In production this will be sure.seams.so, in dev it's 127.0.0.1:8081 ··· 78 78 function getActualUrl(): string { 79 79 const proxyUrl = window.location.href; 80 80 81 - // Try to get from wbinfo (wabac.js/pywb metadata object) 81 + // Try to get from wbinfo (wabac.js metadata object) 82 82 // wabac.js injects this with the original URL 83 83 const wbinfo = (window as any).wbinfo; 84 84 if (wbinfo && wbinfo.url) { 85 85 const rawUrl = wbinfo.url; 86 86 const normalized = normalizeUrl(rawUrl); 87 - console.log('[seams-via] Got URL from wbinfo:', rawUrl); 88 - console.log('[seams-via] Normalized URL:', normalized); 87 + console.log('[seams-client] Got URL from wbinfo:', rawUrl); 88 + console.log('[seams-client] Normalized URL:', normalized); 89 89 return normalized; 90 90 } 91 91 ··· 96 96 if (wabacMatch) { 97 97 const rawUrl = wabacMatch[1]; 98 98 const normalized = normalizeUrl(rawUrl); 99 - console.log('[seams-via] Extracted URL from wabac.js path:', rawUrl); 100 - console.log('[seams-via] Normalized URL:', normalized); 99 + console.log('[seams-client] Extracted URL from wabac.js path:', rawUrl); 100 + console.log('[seams-client] Normalized URL:', normalized); 101 101 return normalized; 102 102 } 103 103 104 - // Fallback: parse from pywb proxy URL 105 - // URL format: http://localhost:8081/proxy/https://example.com 106 - const pywbMatch = proxyUrl.match(/\/proxy\/(https?:\/\/.+)/); 107 - if (pywbMatch) { 108 - const rawUrl = pywbMatch[1]; 109 - const normalized = normalizeUrl(rawUrl); 110 - console.log('[seams-via] Extracted URL from pywb path:', rawUrl); 111 - console.log('[seams-via] Normalized URL:', normalized); 112 - return normalized; 113 - } 114 - 115 - console.warn('[seams-via] Could not extract actual URL, using:', proxyUrl); 104 + console.warn('[seams-client] Could not extract actual URL, using:', proxyUrl); 116 105 return proxyUrl; 117 106 } 118 107
-47
entrypoints/via-client/oauth-callback.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8"> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - <title>Seams OAuth Callback</title> 7 - <style> 8 - body { 9 - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 10 - display: flex; 11 - align-items: center; 12 - justify-content: center; 13 - height: 100vh; 14 - margin: 0; 15 - background: #f5f5f5; 16 - } 17 - .message { 18 - text-align: center; 19 - padding: 32px; 20 - background: white; 21 - border-radius: 8px; 22 - box-shadow: 0 2px 8px rgba(0,0,0,0.1); 23 - } 24 - .spinner { 25 - border: 3px solid #f3f3f3; 26 - border-top: 3px solid #0085ff; 27 - border-radius: 50%; 28 - width: 40px; 29 - height: 40px; 30 - animation: spin 1s linear infinite; 31 - margin: 0 auto 16px; 32 - } 33 - @keyframes spin { 34 - 0% { transform: rotate(0deg); } 35 - 100% { transform: rotate(360deg); } 36 - } 37 - </style> 38 - </head> 39 - <body> 40 - <div class="message"> 41 - <div class="spinner"></div> 42 - <h2>Completing login...</h2> 43 - <p id="status">Processing OAuth response</p> 44 - </div> 45 - <script type="module" src="./oauth-callback.ts"></script> 46 - </body> 47 - </html>
entrypoints/via-client/oauth-callback.ts proxy/src/oauth-callback.ts
entrypoints/via-client/shell.ts proxy/src/shell.ts
-12
entrypoints/via-client/sidebar.html
··· 1 - <!DOCTYPE html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8"> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - <title>Seams Sidebar</title> 7 - </head> 8 - <body> 9 - <div id="app"></div> 10 - <script type="module" src="./sidebar.ts"></script> 11 - </body> 12 - </html>
+137 -95
flake.nix
··· 7 7 beads.url = "github:steveyegge/beads/v0.23.0"; 8 8 }; 9 9 10 - outputs = { self, nixpkgs, flake-utils, beads }: 11 - flake-utils.lib.eachDefaultSystem (system: 10 + outputs = 11 + { 12 + self, 13 + nixpkgs, 14 + flake-utils, 15 + beads, 16 + }: 17 + flake-utils.lib.eachDefaultSystem ( 18 + system: 12 19 let 13 20 pkgs = nixpkgs.legacyPackages.${system}; 14 - 15 - # Path to sure-client-proxy dist (must be built before nix build) 21 + 22 + # Path to proxy dist (must be built before nix build) 16 23 # Requires --impure flag since dist/ is gitignored 17 - # Run: pnpm build:sure-client && nix build .#sureClientProxy --impure 18 - sureClientDistPath = builtins.getEnv "SURE_CLIENT_DIST"; 19 - sureClientDist = if sureClientDistPath != "" 20 - then /. + sureClientDistPath 21 - else builtins.throw "SURE_CLIENT_DIST env var required. Run: SURE_CLIENT_DIST=$PWD/sure-client-proxy/dist nix build .#sureClientProxy --impure"; 22 - 24 + # Run: pnpm build:proxy && nix build .#proxy --impure 25 + proxyDistPath = builtins.getEnv "PROXY_DIST"; 26 + proxyDist = 27 + if proxyDistPath != "" then 28 + /. + proxyDistPath 29 + else 30 + builtins.throw "PROXY_DIST env var required. Run: PROXY_DIST=$PWD/proxy/dist nix build .#proxy --impure"; 31 + 23 32 # Build Go backend server 24 33 server = pkgs.buildGoModule { 25 34 pname = "seams-server"; 26 35 version = "0.1.0"; 27 36 src = ./server; 28 - 37 + 29 38 vendorHash = null; 30 - 39 + 31 40 subPackages = [ "cmd/server" ]; 32 - 41 + 33 42 nativeBuildInputs = [ pkgs.gcc ]; 34 43 }; 35 - 36 - pythonWithPip = pkgs.python311.withPackages (ps: [ ps.pip ]); 44 + 37 45 in 38 46 { 39 47 packages = { ··· 41 49 docker = pkgs.dockerTools.buildImage { 42 50 name = "seams-server"; 43 51 tag = "latest"; 44 - 52 + 45 53 copyToRoot = pkgs.buildEnv { 46 54 name = "image-root"; 47 55 paths = [ 48 56 pkgs.coreutils 49 57 pkgs.bash 50 - pkgs.cacert # Required for HTTPS certificate verification 58 + pkgs.cacert # Required for HTTPS certificate verification 51 59 server 52 - (pkgs.runCommand "static-files" {} '' 60 + (pkgs.runCommand "static-files" { } '' 53 61 mkdir -p $out/app/public 54 62 cp -r ${./landing}/* $out/app/public/ 55 63 '') 56 64 (pkgs.writeScriptBin "start-server.sh" '' 57 65 #!${pkgs.bash}/bin/bash 58 66 set -e 59 - 67 + 60 68 # Create db directory for SQLite (if not already mounted) 61 69 ${pkgs.coreutils}/bin/mkdir -p /app/db 62 - 70 + 63 71 # Start the Go server (serves both API and static files) 64 72 exec ${server}/bin/server 65 73 '') 66 74 ]; 67 - pathsToLink = [ "/bin" "/app" ]; 75 + pathsToLink = [ 76 + "/bin" 77 + "/app" 78 + ]; 68 79 }; 69 - 80 + 70 81 config = { 71 82 Cmd = [ "start-server.sh" ]; 72 - ExposedPorts = { "8080/tcp" = {}; }; 83 + ExposedPorts = { 84 + "8080/tcp" = { }; 85 + }; 73 86 WorkingDir = "/app"; 74 87 Env = [ 75 88 "PORT=8080" ··· 80 93 }; 81 94 }; 82 95 83 - # Docker image for Sure Client Proxy (wabac.js-based) 96 + # Docker image for Proxy (wabac.js-based) 84 97 # Uses Caddy for static files + Node.js CORS proxy 85 - sureClientProxy = pkgs.dockerTools.buildImage { 86 - name = "seams-sure-client-proxy"; 98 + proxy = pkgs.dockerTools.buildImage { 99 + name = "seams-proxy"; 87 100 tag = "latest"; 88 101 89 102 copyToRoot = pkgs.buildEnv { ··· 96 109 pkgs.cacert 97 110 98 111 # Static files and config 99 - # Note: Requires running `pnpm build:sure-client` before building 100 - # to populate sure-client-proxy/dist/ 101 - (pkgs.runCommand "sure-client-files" {} '' 112 + # Note: Requires running `pnpm build:proxy` before building 113 + # to populate proxy/dist/ 114 + (pkgs.runCommand "proxy-files" {} '' 102 115 mkdir -p $out/app/dist 103 116 mkdir -p $out/app/cors-proxy 104 117 105 118 # Copy built static files 106 - cp -r ${sureClientDist}/* $out/app/dist/ 119 + cp -r ${proxyDist}/* $out/app/dist/ 107 120 108 121 # Copy CORS proxy source 109 - cp -r ${./sure-client-proxy/cors-proxy}/* $out/app/cors-proxy/ 122 + cp -r ${./proxy/cors-proxy}/* $out/app/cors-proxy/ 110 123 111 124 # Copy Caddyfile 112 - cp ${./sure-client-proxy/Caddyfile} $out/app/Caddyfile 125 + cp ${./proxy/Caddyfile} $out/app/Caddyfile 113 126 '') 114 127 115 128 # Startup script 116 - (pkgs.writeScriptBin "start-sure-client.sh" '' 129 + (pkgs.writeScriptBin "start-proxy.sh" '' 117 130 #!${pkgs.bash}/bin/bash 118 131 set -e 119 132 120 - echo "Starting Seams Sure Client Proxy..." 133 + echo "Starting Seams Proxy..." 121 134 122 135 # Ensure HOME exists for npm 123 136 ${pkgs.coreutils}/bin/mkdir -p /root ··· 145 158 }; 146 159 147 160 config = { 148 - Cmd = [ "start-sure-client.sh" ]; 161 + Cmd = [ "start-proxy.sh" ]; 149 162 ExposedPorts = { "8081/tcp" = {}; "8082/tcp" = {}; }; 150 163 WorkingDir = "/app"; 151 164 Env = [ ··· 157 170 ]; 158 171 }; 159 172 }; 173 + }; 174 + 175 + config = { 176 + Cmd = [ "start-sure-client.sh" ]; 177 + ExposedPorts = { 178 + "8081/tcp" = { }; 179 + "8082/tcp" = { }; 180 + }; 181 + WorkingDir = "/app"; 182 + Env = [ 183 + "PATH=/bin" 184 + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" 185 + "HOME=/root" 186 + # Default CORS origins - override with CORS_ALLOWED_ORIGINS env var 187 + "CORS_ALLOWED_ORIGINS=http://localhost:8081,http://127.0.0.1:8081" 188 + ]; 189 + }; 190 + }; 160 191 161 192 # Docker image for Via Proxy (pywb-based, legacy) 162 193 proxy = pkgs.dockerTools.buildImage { 163 194 name = "seams-proxy"; 164 195 tag = "latest"; 165 - 196 + 166 197 copyToRoot = pkgs.buildEnv { 167 198 name = "image-root"; 168 199 paths = [ ··· 175 206 pkgs.gcc 176 207 pkgs.cacert 177 208 pkgs.stdenv.cc.cc.lib # For pywb/gevent dependencies 178 - 209 + 179 210 # Config and static files 180 211 # Note: This relies on proxy/static being populated by running: 181 212 # BACKEND_URL=https://seams.so pnpm build:via 182 213 # locally before building. The BACKEND_URL must be set for production! 183 214 # and included in the source tree (e.g. git tracked or added). 184 - (pkgs.runCommand "proxy-files" {} '' 215 + (pkgs.runCommand "proxy-files" { } '' 185 216 mkdir -p $out/app/proxy 186 217 cp -r ${./proxy}/* $out/app/proxy/ 187 218 cp ${./Caddyfile} $out/app/Caddyfile 188 219 '') 189 - 220 + 190 221 # Startup script 191 222 (pkgs.writeScriptBin "start-proxy.sh" '' 192 223 #!${pkgs.bash}/bin/bash 193 224 set -e 194 - 225 + 195 226 echo "🚀 Starting Seams Proxy..." 196 - 227 + 197 228 # Install pywb at runtime using uv 198 229 echo "📦 Installing pywb..." 199 230 # Ensure HOME exists 200 231 ${pkgs.coreutils}/bin/mkdir -p /root 201 - 232 + 202 233 export UV_CACHE_DIR=/root/.cache/uv 203 234 export UV_TOOL_BIN_DIR=/root/.local/bin 204 235 ${pkgs.uv}/bin/uv tool install pywb --with setuptools --python ${pythonWithPip}/bin/python3 205 - 236 + 206 237 # Add local bin to PATH (where uv installs tools) 207 238 export PATH=$PATH:/root/.local/bin 208 - 239 + 209 240 # Start wayback (pywb) on port 8081 210 241 # Must run from proxy dir to find config.yaml 211 242 cd /app/proxy ··· 214 245 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${pkgs.glibc}/lib 215 246 wayback -p 8081 -b 127.0.0.1 & 216 247 WB_PID=$! 217 - 248 + 218 249 # Wait for wayback to initialize 219 250 ${pkgs.coreutils}/bin/sleep 2 220 - 251 + 221 252 # Start Caddy on port 8082 222 253 cd /app 223 254 echo "🌐 Starting Caddy on :8082" 224 255 ${pkgs.caddy}/bin/caddy run --config /app/Caddyfile --adapter caddyfile 225 256 '') 226 257 ]; 227 - pathsToLink = [ "/bin" "/app" ]; 258 + pathsToLink = [ 259 + "/bin" 260 + "/app" 261 + ]; 228 262 }; 229 - 263 + 230 264 config = { 231 265 Cmd = [ "start-proxy.sh" ]; 232 - ExposedPorts = { "8082/tcp" = {}; "8081/tcp" = {}; }; 266 + ExposedPorts = { 267 + "8082/tcp" = { }; 268 + "8081/tcp" = { }; 269 + }; 233 270 WorkingDir = "/app"; 234 271 Env = [ 235 272 "PATH=/bin" ··· 240 277 }; 241 278 }; 242 279 }; 243 - 280 + 244 281 devShells = { 245 282 # Default: Full development environment (Extension + Server) 246 283 default = pkgs.mkShell { 247 - buildInputs = with pkgs; [ 248 - beads.packages.${system}.default 249 - bun 250 - nodejs_22 251 - pnpm 252 - typescript 253 - git 254 - curl 255 - jq 256 - go 257 - sqlite 258 - gcc 259 - air 260 - dnscontrol 261 - caddy 262 - python311 263 - uv 264 - stdenv.cc.cc.lib 265 - ] ++ (if pkgs.stdenv.isLinux then [ chromium ] else []); 284 + buildInputs = 285 + with pkgs; 286 + [ 287 + beads.packages.${system}.default 288 + bun 289 + nodejs_22 290 + pnpm 291 + typescript 292 + git 293 + curl 294 + jq 295 + go 296 + sqlite 297 + gcc 298 + air 299 + dnscontrol 300 + caddy 301 + python311 302 + uv 303 + stdenv.cc.cc.lib 304 + ] 305 + ++ (if pkgs.stdenv.isLinux then [ chromium ] else [ ]); 266 306 267 307 shellHook = '' 268 308 export PATH="$PWD/node_modules/.bin:$PATH" 269 309 export API_PORT=''${API_PORT:-3000} 270 310 export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH" 271 - 272 - echo "🚀 Full development environment (Extension + Server)" 311 + 312 + echo "Full development environment (Extension + Server)" 273 313 echo "" 274 - echo "Extension: pnpm dev, pnpm build, pnpm zip, pnpm via" 314 + echo "Extension: pnpm dev, pnpm build, pnpm zip" 275 315 echo "Server: cd server && air" 276 316 ''; 277 317 }; 278 318 279 319 # Extension-only development shell 280 320 extension = pkgs.mkShell { 281 - buildInputs = with pkgs; [ 282 - beads.packages.${system}.default 283 - bun 284 - nodejs_22 285 - pnpm 286 - typescript 287 - git 288 - curl 289 - jq 290 - caddy 291 - python311 292 - uv 293 - stdenv.cc.cc.lib 294 - ] ++ (if pkgs.stdenv.isLinux then [ chromium ] else []); 321 + buildInputs = 322 + with pkgs; 323 + [ 324 + beads.packages.${system}.default 325 + bun 326 + nodejs_22 327 + pnpm 328 + typescript 329 + git 330 + curl 331 + jq 332 + caddy 333 + python311 334 + uv 335 + stdenv.cc.cc.lib 336 + ] 337 + ++ (if pkgs.stdenv.isLinux then [ chromium ] else [ ]); 295 338 296 339 shellHook = '' 297 340 export PATH="$PWD/node_modules/.bin:$PATH" 298 341 export API_PORT=''${API_PORT:-3000} 299 342 export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH" 300 - 301 - echo "🌐 Extension development environment" 343 + 344 + echo "Extension development environment" 302 345 echo "Commands:" 303 346 echo " pnpm dev - Extension development server" 304 347 echo " pnpm build - Build extension" 305 - echo " pnpm via - Start via proxy (http://localhost:8082)" 306 348 ''; 307 349 }; 308 350 ··· 316 358 ]; 317 359 318 360 shellHook = '' 319 - echo "🔧 Go backend development environment" 361 + echo "Go backend development environment" 320 362 echo "Go version: $(go version)" 321 363 echo "" 322 364 echo "Commands:" ··· 326 368 echo " cd server && go mod tidy - Update dependencies" 327 369 ''; 328 370 }; 371 + }; 329 372 330 373 # Via proxy development environment (Caddy + pywb) 331 374 via = pkgs.mkShell { 332 375 buildInputs = with pkgs; [ 333 376 caddy 334 - wayback # Add wayback from nixpkgs 377 + wayback # Add wayback from nixpkgs 335 378 python311 336 379 uv 337 380 nodejs_20 338 381 pnpm 339 382 ]; 340 - 383 + 341 384 shellHook = '' 342 385 echo "🌐 Via proxy development environment" 343 386 echo "" ··· 352 395 echo " 3. Visit http://localhost:8082" 353 396 ''; 354 397 }; 355 - 398 + 356 399 # pywb proxy test environment (legacy) 357 400 pywb = pkgs.mkShell { 358 401 buildInputs = with pkgs; [ ··· 363 406 364 407 shellHook = '' 365 408 export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH" 366 - 409 + 367 410 echo "🔬 pywb test environment" 368 411 echo "" 369 412 echo "Quick start:" ··· 376 419 } 377 420 ); 378 421 } 379 -
+17 -3
fly.proxy.toml
··· 1 - # fly.proxy.toml app configuration file for sure.seams.so (Proxy) 1 + # fly.proxy.toml app configuration for Proxy (wabac.js-based) 2 + # Deploy with: ./deploy-proxy.sh 2 3 app = 'sure-seams-so' 3 4 primary_region = 'sjc' 4 5 5 6 [build] 6 7 dockerfile = "Dockerfile.proxy" 7 8 9 + # Main service on port 8081 (static files) 8 10 [http_service] 9 - internal_port = 8082 11 + internal_port = 8081 10 12 force_https = true 11 - auto_stop_machines = true 13 + auto_stop_machines = 'stop' 12 14 auto_start_machines = true 13 15 min_machines_running = 1 14 16 processes = ['app'] 15 17 18 + # Also expose CORS proxy on port 8082 19 + [[services]] 20 + internal_port = 8082 21 + protocol = "tcp" 22 + [[services.ports]] 23 + handlers = ["tls", "http"] 24 + port = 8082 25 + 16 26 [[vm]] 17 27 memory = '512mb' 18 28 cpu_kind = 'shared' 19 29 cpus = 1 30 + 31 + [env] 32 + # Production domains - include both the fly.dev domain and custom domain 33 + CORS_ALLOWED_ORIGINS = "https://sure.seams.so,https://sure-client-seams-so.fly.dev"
-33
fly.sure-client.toml
··· 1 - # fly.sure-client.toml app configuration for Sure Client Proxy (wabac.js-based) 2 - # Deploy with: ./deploy-sure-client.sh 3 - app = 'sure-seams-so' 4 - primary_region = 'sjc' 5 - 6 - [build] 7 - dockerfile = "Dockerfile.sure-client" 8 - 9 - # Main service on port 8081 (static files) 10 - [http_service] 11 - internal_port = 8081 12 - force_https = true 13 - auto_stop_machines = 'stop' 14 - auto_start_machines = true 15 - min_machines_running = 1 16 - processes = ['app'] 17 - 18 - # Also expose CORS proxy on port 8082 19 - [[services]] 20 - internal_port = 8082 21 - protocol = "tcp" 22 - [[services.ports]] 23 - handlers = ["tls", "http"] 24 - port = 8082 25 - 26 - [[vm]] 27 - memory = '512mb' 28 - cpu_kind = 'shared' 29 - cpus = 1 30 - 31 - [env] 32 - # Production domains - include both the fly.dev domain and custom domain 33 - CORS_ALLOWED_ORIGINS = "https://sure.seams.so,https://sure-client-seams-so.fly.dev"
-170
history/PROXY_STABILITY_PLAN.md
··· 1 - # Proxy Stability Plan: sure.seams.so 2 - 3 - ## Problem Statement 4 - 5 - On 2025-12-06, the `sure.seams.so` proxy became unresponsive. Users saw: 6 - ``` 7 - [PR03] could not find a good candidate within 1 attempts at load balancing. 8 - last error: [PU03] unreachable worker host. the host may be unhealthy. this is a Fly issue. 9 - ``` 10 - 11 - ### Root Cause Analysis 12 - 13 - Investigation revealed: 14 - 1. **pywb requests were hanging indefinitely** - Logs showed requests taking 500+ seconds with `status: 0` (connection closed without response) 15 - 2. **Accumulated stuck connections** - `/proc/net/tcp` showed many connections in CLOSE_WAIT state 16 - 3. **No request timeouts** - pywb's `wayback` CLI has no built-in timeout for upstream fetches 17 - 4. **No health checks** - Fly.io couldn't detect pywb was stuck (only Caddy was responding) 18 - 5. **No process supervision** - `wayback` ran in background with `&`, no restart on failure 19 - 20 - ### Immediate Fix 21 - A redeployment (`flyctl deploy -c fly.proxy.toml --no-cache`) cleared the stuck state. 22 - 23 - --- 24 - 25 - ## Current Architecture 26 - 27 - ``` 28 - Internet → Fly.io (TLS) → Caddy (:8082) → pywb/wayback (:8081) 29 - ``` 30 - 31 - ### Current Dockerfile.proxy 32 - - Runs `wayback -p 8081` in background 33 - - Runs Caddy in foreground on :8082 34 - - Caddy proxies `/proxy/*` and `/static/*` to pywb 35 - - Caddy serves static files for OAuth callback, .well-known, etc. 36 - 37 - ### What Caddy Currently Does 38 - 1. **Proxies to pywb**: `/proxy/*`, `/static/*` 39 - 2. **Serves static files**: OAuth callback, .well-known (TWA), CSS/JS 40 - 3. **Redirects**: Root `/` → seams.so 41 - 4. **Strips CSP headers** from proxied responses 42 - 43 - ### OAuth Flow on sure.seams.so 44 - - Redirect URI: `https://sure.seams.so/oauth-callback.html` 45 - - Callback page: `proxy/static/oauth-callback.html` (built from `entrypoints/via-client/oauth-callback.ts`) 46 - - Uses same client_id as main extension: `https://seams.so/oauth/client-metadata.json` 47 - 48 - --- 49 - 50 - ## Proposed Solution 51 - 52 - ### Key Insight from pywb Documentation 53 - pywb recommends **uwsgi with gevent** for production, not the `wayback` CLI: 54 - 55 - > "For larger scale production deployments, running with uwsgi server application is recommended... 56 - > pywb must be run with the Gevent Loop Engine." 57 - 58 - ### Changes Required 59 - 60 - #### 1. Replace `wayback` CLI with `uwsgi` 61 - **Why**: uwsgi provides worker management, request timeouts, and automatic recycling. 62 - 63 - **uwsgi.ini settings needed**: 64 - ```ini 65 - [uwsgi] 66 - http-socket = :8080 67 - master = true 68 - gevent = 100 69 - harakiri = 30 # Kill requests stuck >30 seconds 70 - harakiri-verbose = true 71 - die-on-term = true 72 - env = PYWB_CONFIG_FILE=config.yaml 73 - wsgi = pywb.apps.wayback 74 - ``` 75 - 76 - #### 2. Remove Caddy (Evaluate First) 77 - **Why**: Simplify architecture, fewer moving parts. 78 - 79 - **Caddy's current responsibilities that must be handled**: 80 - | Route | Current Handler | Replacement | 81 - |-------|-----------------|-------------| 82 - | `/proxy/*` | Caddy → pywb | uwsgi directly | 83 - | `/static/*` | Caddy → pywb | pywb `static_routes` | 84 - | `/oauth-callback.html` | Caddy file_server | pywb `static_routes` | 85 - | `/.well-known/*` | Caddy file_server | pywb `static_routes` | 86 - | `/` | Caddy redirect | pywb or uwsgi config | 87 - | CSP header stripping | Caddy `header_down` | pywb config `enable_content_security_policy: false` | 88 - 89 - **Risk**: OAuth callback must work. This is critical path for user login. 90 - 91 - #### 3. Add Fly.io Health Check 92 - **Why**: Detect and restart unhealthy machines automatically. 93 - 94 - ```toml 95 - # fly.proxy.toml 96 - [[services.http_checks]] 97 - interval = "10s" 98 - timeout = "5s" 99 - path = "/proxy/https://example.com/" 100 - method = "HEAD" 101 - ``` 102 - 103 - --- 104 - 105 - ## Success Criteria 106 - 107 - ### Functional Requirements 108 - - [ ] Proxy serves pages: `https://sure.seams.so/proxy/https://example.com/` returns 200 109 - - [ ] OAuth callback works: User can log in via sure.seams.so sidebar 110 - - [ ] Static files served: `/static/*` routes work for seams-client.js, CSS 111 - - [ ] .well-known served: TWA asset links accessible 112 - - [ ] Seams sidebar injects and functions on proxied pages 113 - 114 - ### Stability Requirements 115 - - [ ] Requests timeout after 30 seconds (not hang indefinitely) 116 - - [ ] Health check detects stuck pywb and triggers restart 117 - - [ ] No zombie process accumulation over 24+ hours 118 - - [ ] Clean shutdown on SIGTERM (Fly.io deployments) 119 - 120 - ### Testing Checklist 121 - 1. **Basic proxy**: `curl -I https://sure.seams.so/proxy/https://example.com/` 122 - 2. **OAuth flow**: Log in via sure.seams.so sidebar, verify session persists 123 - 3. **Static files**: `curl https://sure.seams.so/static/seams-client.js` 124 - 4. **TWA links**: `curl https://sure.seams.so/.well-known/assetlinks.json` 125 - 5. **Timeout behavior**: Request a slow/hanging URL, verify 30s timeout 126 - 6. **Health check**: `flyctl checks list -a sure-seams-so` 127 - 128 - --- 129 - 130 - ## Implementation Steps 131 - 132 - ### Phase 1: Prepare (No Deployment) 133 - 1. Clean up git history (commit current OAuth callback fixes) 134 - 2. Create new branch for proxy stability work 135 - 3. Update pywb config.yaml to serve all static routes 136 - 4. Write uwsgi.ini with harakiri timeout 137 - 5. Update Dockerfile.proxy to use uwsgi 138 - 139 - ### Phase 2: Test Locally 140 - 1. Build and run container locally 141 - 2. Test all routes from checklist 142 - 3. Verify OAuth callback flow works 143 - 144 - ### Phase 3: Deploy to Staging (Optional) 145 - 1. Deploy to separate Fly.io app for testing 146 - 2. Full test checklist 147 - 148 - ### Phase 4: Production Deploy 149 - 1. Deploy to sure-seams-so 150 - 2. Monitor logs for 24 hours 151 - 3. Verify no stuck processes accumulate 152 - 153 - --- 154 - 155 - ## Rollback Plan 156 - 157 - If issues arise after deployment: 158 - ```bash 159 - # Revert to previous Docker image 160 - flyctl releases -a sure-seams-so 161 - flyctl deploy -a sure-seams-so --image registry.fly.io/sure-seams-so:deployment-<PREVIOUS_ID> 162 - ``` 163 - 164 - --- 165 - 166 - ## References 167 - - [pywb Deployment Guide](https://pywb.readthedocs.io/en/latest/manual/usage.html#deployment) 168 - - [pywb Docker Image](https://github.com/webrecorder/pywb/blob/main/Dockerfile) 169 - - [uwsgi.ini reference](https://github.com/webrecorder/pywb/blob/main/uwsgi.ini) 170 - - [Fly.io Health Checks](https://fly.io/docs/reference/configuration/#services-http_checks)
+5 -5
package.json
··· 8 8 "build": "wxt build", 9 9 "zip": "wxt zip -b firefox && wxt zip -b chrome", 10 10 "build:landing": "vite build --config vite.landing.config.ts", 11 - "build:via": "vite build --config vite.via.config.ts && bash scripts/postbuild-via.sh", 12 - "dev:via": "vite build --config vite.via.config.ts --watch", 13 - "build:sure-client": "vite build --config vite.sure-client.config.ts && vite build --config vite.sure-client-inject.config.ts && bash scripts/postbuild-sure-client.sh", 14 - "dev:sure-client": "vite build --config vite.sure-client-inject.config.ts --watch", 11 + "build:proxy": "vite build --config vite.proxy.config.ts && vite build --config vite.proxy-inject.config.ts && bash scripts/postbuild-proxy.sh", 12 + "dev:proxy": "pnpm build:proxy && concurrently \"cd proxy/cors-proxy && npm run dev\" \"npx serve proxy/dist -l 8081\"", 15 13 "dev:server": "pnpm run build:landing && cd server && air", 16 - "via": "bash scripts/start-via.sh", 17 14 "test": "pnpm --filter @seams/core test", 18 15 "test:coverage": "pnpm --filter @seams/core test:coverage", 19 16 "test:watch": "pnpm --filter @seams/core test:watch", ··· 45 42 "devDependencies": { 46 43 "@flydotio/dockerfile": "^0.7.10", 47 44 "@playwright/test": "^1.57.0", 45 + "concurrently": "^9.2.1", 46 + "knip": "^5.80.1", 47 + "serve": "^14.2.5", 48 48 "vite": "^5.0.0", 49 49 "wxt": "0.20.9" 50 50 },
+1 -1
packages/core/src/utils/highlights/popover.ts
··· 1 - import type { Annotation } from '../types/annotation'; 1 + import type { Annotation } from '../../types'; 2 2 import { escapeHtml } from '../sanitize'; 3 3 4 4 let currentPopover: HTMLElement | null = null;
+1 -1
packages/core/src/utils/selectors/match.ts
··· 1 1 import * as textQuote from 'dom-anchor-text-quote'; 2 2 import * as textPosition from 'dom-anchor-text-position'; 3 - import type { Annotation, TextQuoteSelector, TextPositionSelector } from '../types/annotation'; 3 + import type { Annotation, TextQuoteSelector, TextPositionSelector } from '../../types'; 4 4 5 5 /** 6 6 * Find the DOM Range for an annotation using its selectors
+755
pnpm-lock.yaml
··· 33 33 '@playwright/test': 34 34 specifier: ^1.57.0 35 35 version: 1.57.0 36 + concurrently: 37 + specifier: ^9.2.1 38 + version: 9.2.1 39 + knip: 40 + specifier: ^5.80.1 41 + version: 5.80.1(@types/node@24.8.1)(typescript@5.9.3) 42 + serve: 43 + specifier: ^14.2.5 44 + version: 14.2.5 36 45 vite: 37 46 specifier: ^5.0.0 38 47 version: 5.4.21(@types/node@24.8.1) ··· 171 180 resolution: {integrity: sha512-7rBLLzWQnBwutH2WZ0EWUkQdihqrnLYCUMaB44hSol9e0/cdIhuNFcqZO0xNheAU6qqHVA8sMiLofkYTgb+lmw==} 172 181 engines: {node: '>= 0.10.4'} 173 182 hasBin: true 183 + 184 + '@emnapi/core@1.8.1': 185 + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} 186 + 187 + '@emnapi/runtime@1.8.1': 188 + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} 189 + 190 + '@emnapi/wasi-threads@1.1.0': 191 + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} 174 192 175 193 '@esbuild/aix-ppc64@0.21.5': 176 194 resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} ··· 785 803 '@jridgewell/trace-mapping@0.3.31': 786 804 resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 787 805 806 + '@napi-rs/wasm-runtime@1.1.1': 807 + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} 808 + 788 809 '@nodelib/fs.scandir@2.1.5': 789 810 resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 790 811 engines: {node: '>= 8'} ··· 797 818 resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 798 819 engines: {node: '>= 8'} 799 820 821 + '@oxc-resolver/binding-android-arm-eabi@11.16.2': 822 + resolution: {integrity: sha512-lVJbvydLQIDZHKUb6Zs9Rq80QVTQ9xdCQE30eC9/cjg4wsMoEOg65QZPymUAIVJotpUAWJD0XYcwE7ugfxx5kQ==} 823 + cpu: [arm] 824 + os: [android] 825 + 826 + '@oxc-resolver/binding-android-arm64@11.16.2': 827 + resolution: {integrity: sha512-fEk+g/g2rJ6LnBVPqeLcx+/alWZ/Db1UlXG+ZVivip0NdrnOzRL48PAmnxTMGOrLwsH1UDJkwY3wOjrrQltCqg==} 828 + cpu: [arm64] 829 + os: [android] 830 + 831 + '@oxc-resolver/binding-darwin-arm64@11.16.2': 832 + resolution: {integrity: sha512-Pkbp1qi7kdUX6k3Fk1PvAg6p7ruwaWKg1AhOlDgrg2vLXjtv9ZHo7IAQN6kLj0W771dPJZWqNxoqTPacp2oYWA==} 833 + cpu: [arm64] 834 + os: [darwin] 835 + 836 + '@oxc-resolver/binding-darwin-x64@11.16.2': 837 + resolution: {integrity: sha512-FYCGcU1iSoPkADGLfQbuj0HWzS+0ItjDCt9PKtu2Hzy6T0dxO4Y1enKeCOxCweOlmLEkSxUlW5UPT4wvT3LnAg==} 838 + cpu: [x64] 839 + os: [darwin] 840 + 841 + '@oxc-resolver/binding-freebsd-x64@11.16.2': 842 + resolution: {integrity: sha512-1zHCoK6fMcBjE54P2EG/z70rTjcRxvyKfvk4E/QVrWLxNahuGDFZIxoEoo4kGnnEcmPj41F0c2PkrQbqlpja5g==} 843 + cpu: [x64] 844 + os: [freebsd] 845 + 846 + '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.2': 847 + resolution: {integrity: sha512-+ucLYz8EO5FDp6kZ4o1uDmhoP+M98ysqiUW4hI3NmfiOJQWLrAzQjqaTdPfIOzlCXBU9IHp5Cgxu6wPjVb8dbA==} 848 + cpu: [arm] 849 + os: [linux] 850 + 851 + '@oxc-resolver/binding-linux-arm-musleabihf@11.16.2': 852 + resolution: {integrity: sha512-qq+TpNXyw1odDgoONRpMLzH4hzhwnEw55398dL8rhKGvvYbio71WrJ00jE+hGlEi7H1Gkl11KoPJRaPlRAVGPw==} 853 + cpu: [arm] 854 + os: [linux] 855 + 856 + '@oxc-resolver/binding-linux-arm64-gnu@11.16.2': 857 + resolution: {integrity: sha512-xlMh4gNtplNQEwuF5icm69udC7un0WyzT5ywOeHrPMEsghKnLjXok2wZgAA7ocTm9+JsI+nVXIQa5XO1x+HPQg==} 858 + cpu: [arm64] 859 + os: [linux] 860 + 861 + '@oxc-resolver/binding-linux-arm64-musl@11.16.2': 862 + resolution: {integrity: sha512-OZs33QTMi0xmHv/4P0+RAKXJTBk7UcMH5tpTaCytWRXls/DGaJ48jOHmriQGK2YwUqXl+oneuNyPOUO0obJ+Hg==} 863 + cpu: [arm64] 864 + os: [linux] 865 + 866 + '@oxc-resolver/binding-linux-ppc64-gnu@11.16.2': 867 + resolution: {integrity: sha512-UVyuhaV32dJGtF6fDofOcBstg9JwB2Jfnjfb8jGlu3xcG+TsubHRhuTwQ6JZ1sColNT1nMxBiu7zdKUEZi1kwg==} 868 + cpu: [ppc64] 869 + os: [linux] 870 + 871 + '@oxc-resolver/binding-linux-riscv64-gnu@11.16.2': 872 + resolution: {integrity: sha512-YZZS0yv2q5nE1uL/Fk4Y7m9018DSEmDNSG8oJzy1TJjA1jx5HL52hEPxi98XhU6OYhSO/vC1jdkJeE8TIHugug==} 873 + cpu: [riscv64] 874 + os: [linux] 875 + 876 + '@oxc-resolver/binding-linux-riscv64-musl@11.16.2': 877 + resolution: {integrity: sha512-9VYuypwtx4kt1lUcwJAH4dPmgJySh4/KxtAPdRoX2BTaZxVm/yEXHq0mnl/8SEarjzMvXKbf7Cm6UBgptm3DZw==} 878 + cpu: [riscv64] 879 + os: [linux] 880 + 881 + '@oxc-resolver/binding-linux-s390x-gnu@11.16.2': 882 + resolution: {integrity: sha512-3gbwQ+xlL5gpyzgSDdC8B4qIM4mZaPDLaFOi3c/GV7CqIdVJc5EZXW4V3T6xwtPBOpXPXfqQLbhTnUD4SqwJtA==} 883 + cpu: [s390x] 884 + os: [linux] 885 + 886 + '@oxc-resolver/binding-linux-x64-gnu@11.16.2': 887 + resolution: {integrity: sha512-m0WcK0j54tSwWa+hQaJMScZdWneqE7xixp/vpFqlkbhuKW9dRHykPAFvSYg1YJ3MJgu9ZzVNpYHhPKJiEQq57Q==} 888 + cpu: [x64] 889 + os: [linux] 890 + 891 + '@oxc-resolver/binding-linux-x64-musl@11.16.2': 892 + resolution: {integrity: sha512-ZjUm3w96P2t47nWywGwj1A2mAVBI/8IoS7XHhcogWCfXnEI3M6NPIRQPYAZW4s5/u3u6w1uPtgOwffj2XIOb/g==} 893 + cpu: [x64] 894 + os: [linux] 895 + 896 + '@oxc-resolver/binding-openharmony-arm64@11.16.2': 897 + resolution: {integrity: sha512-OFVQ2x3VenTp13nIl6HcQ/7dmhFmM9dg2EjKfHcOtYfrVLQdNR6THFU7GkMdmc8DdY1zLUeilHwBIsyxv5hkwQ==} 898 + cpu: [arm64] 899 + os: [openharmony] 900 + 901 + '@oxc-resolver/binding-wasm32-wasi@11.16.2': 902 + resolution: {integrity: sha512-+O1sY3RrGyA2AqDnd3yaDCsqZqCblSTEpY7TbbaOaw0X7iIbGjjRLdrQk9StG3QSiZuBy9FdFwotIiSXtwvbAQ==} 903 + engines: {node: '>=14.0.0'} 904 + cpu: [wasm32] 905 + 906 + '@oxc-resolver/binding-win32-arm64-msvc@11.16.2': 907 + resolution: {integrity: sha512-jMrMJL+fkx6xoSMFPOeyQ1ctTFjavWPOSZEKUY5PebDwQmC9cqEr4LhdTnGsOtFrWYLXlEU4xWeMdBoc/XKkOA==} 908 + cpu: [arm64] 909 + os: [win32] 910 + 911 + '@oxc-resolver/binding-win32-ia32-msvc@11.16.2': 912 + resolution: {integrity: sha512-tl0xDA5dcQplG2yg2ZhgVT578dhRFafaCfyqMEAXq8KNpor85nJ53C3PLpfxD2NKzPioFgWEexNsjqRi+kW2Mg==} 913 + cpu: [ia32] 914 + os: [win32] 915 + 916 + '@oxc-resolver/binding-win32-x64-msvc@11.16.2': 917 + resolution: {integrity: sha512-M7z0xjYQq1HdJk2DxTSLMvRMyBSI4wn4FXGcVQBsbAihgXevAReqwMdb593nmCK/OiFwSNcOaGIzUvzyzQ+95w==} 918 + cpu: [x64] 919 + os: [win32] 920 + 800 921 '@playwright/test@1.57.0': 801 922 resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} 802 923 engines: {node: '>=18'} ··· 927 1048 '@standard-schema/spec@1.0.0': 928 1049 resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} 929 1050 1051 + '@tybys/wasm-util@0.10.1': 1052 + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} 1053 + 930 1054 '@types/chai@5.2.3': 931 1055 resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 932 1056 ··· 1013 1137 '@wxt-dev/storage@1.2.0': 1014 1138 resolution: {integrity: sha512-4A44zCpwl5GZdmUdSJvUWJ6ekZZ+Fz5ttYqTGPIRJSsyosKX8X8Yl7D2Loy1ZlqIg6oJHysaiFXALtTE+pFjpw==} 1015 1139 1140 + '@zeit/schemas@2.36.0': 1141 + resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} 1142 + 1016 1143 acorn@8.15.0: 1017 1144 resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 1018 1145 engines: {node: '>=0.4.0'} ··· 1021 1148 adm-zip@0.5.16: 1022 1149 resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} 1023 1150 engines: {node: '>=12.0'} 1151 + 1152 + ajv@8.12.0: 1153 + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} 1024 1154 1025 1155 ancestors@0.0.3: 1026 1156 resolution: {integrity: sha512-hWePu8BinW3M5wSo2++ahS6mb3ZZcYWFIxrmOfJI4990DRQnM/OrMNWorjVotrrAkVxldBdF17TCKenwin4XzA==} ··· 1051 1181 any-promise@1.3.0: 1052 1182 resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 1053 1183 1184 + arch@2.2.0: 1185 + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} 1186 + 1187 + arg@5.0.2: 1188 + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 1189 + 1190 + argparse@2.0.1: 1191 + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 1192 + 1054 1193 array-differ@4.0.0: 1055 1194 resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} 1056 1195 engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} ··· 1097 1236 boolbase@1.0.0: 1098 1237 resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} 1099 1238 1239 + boxen@7.0.0: 1240 + resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} 1241 + engines: {node: '>=14.16'} 1242 + 1100 1243 boxen@8.0.1: 1101 1244 resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} 1102 1245 engines: {node: '>=18'} ··· 1124 1267 resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} 1125 1268 engines: {node: '>=18'} 1126 1269 1270 + bytes@3.0.0: 1271 + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} 1272 + engines: {node: '>= 0.8'} 1273 + 1274 + bytes@3.1.2: 1275 + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 1276 + engines: {node: '>= 0.8'} 1277 + 1127 1278 c12@3.3.1: 1128 1279 resolution: {integrity: sha512-LcWQ01LT9tkoUINHgpIOv3mMs+Abv7oVCrtpMRi1PaapVEpWoMga5WuT7/DqFTu7URP9ftbOmimNw1KNIGh9DQ==} 1129 1280 peerDependencies: ··· 1136 1287 resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 1137 1288 engines: {node: '>=8'} 1138 1289 1290 + camelcase@7.0.1: 1291 + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} 1292 + engines: {node: '>=14.16'} 1293 + 1139 1294 camelcase@8.0.0: 1140 1295 resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} 1141 1296 engines: {node: '>=16'} ··· 1143 1298 chai@6.2.2: 1144 1299 resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} 1145 1300 engines: {node: '>=18'} 1301 + 1302 + chalk-template@0.4.0: 1303 + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} 1304 + engines: {node: '>=12'} 1146 1305 1147 1306 chalk@4.1.2: 1148 1307 resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 1149 1308 engines: {node: '>=10'} 1309 + 1310 + chalk@5.0.1: 1311 + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} 1312 + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 1150 1313 1151 1314 chalk@5.6.2: 1152 1315 resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} ··· 1200 1363 resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} 1201 1364 engines: {node: '>= 12'} 1202 1365 1366 + clipboardy@3.0.0: 1367 + resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} 1368 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1369 + 1203 1370 cliui@7.0.4: 1204 1371 resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} 1205 1372 ··· 1229 1396 resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} 1230 1397 engines: {node: ^12.20.0 || >=14} 1231 1398 1399 + compressible@2.0.18: 1400 + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} 1401 + engines: {node: '>= 0.6'} 1402 + 1403 + compression@1.8.1: 1404 + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} 1405 + engines: {node: '>= 0.8.0'} 1406 + 1232 1407 concat-map@0.0.1: 1233 1408 resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 1234 1409 ··· 1236 1411 resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} 1237 1412 engines: {'0': node >= 0.8} 1238 1413 1414 + concurrently@9.2.1: 1415 + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} 1416 + engines: {node: '>=18'} 1417 + hasBin: true 1418 + 1239 1419 confbox@0.1.8: 1240 1420 resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 1241 1421 ··· 1252 1432 consola@3.4.2: 1253 1433 resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} 1254 1434 engines: {node: ^14.18.0 || >=16.10.0} 1435 + 1436 + content-disposition@0.5.2: 1437 + resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} 1438 + engines: {node: '>= 0.6'} 1255 1439 1256 1440 core-util-is@1.0.3: 1257 1441 resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 1258 1442 1443 + cross-spawn@7.0.6: 1444 + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 1445 + engines: {node: '>= 8'} 1446 + 1259 1447 css-select@5.2.2: 1260 1448 resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} 1261 1449 ··· 1269 1457 debounce@1.2.1: 1270 1458 resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} 1271 1459 1460 + debug@2.6.9: 1461 + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} 1462 + peerDependencies: 1463 + supports-color: '*' 1464 + peerDependenciesMeta: 1465 + supports-color: 1466 + optional: true 1467 + 1272 1468 debug@4.3.7: 1273 1469 resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} 1274 1470 engines: {node: '>=6.0'} ··· 1374 1570 resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} 1375 1571 engines: {node: '>=12'} 1376 1572 1573 + eastasianwidth@0.2.0: 1574 + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 1575 + 1377 1576 ejs@3.1.10: 1378 1577 resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} 1379 1578 engines: {node: '>=0.10.0'} ··· 1385 1584 emoji-regex@8.0.0: 1386 1585 resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 1387 1586 1587 + emoji-regex@9.2.2: 1588 + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 1589 + 1388 1590 end-of-stream@1.4.5: 1389 1591 resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} 1390 1592 ··· 1449 1651 eventemitter3@5.0.1: 1450 1652 resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} 1451 1653 1654 + execa@5.1.1: 1655 + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 1656 + engines: {node: '>=10'} 1657 + 1452 1658 expect-type@1.3.0: 1453 1659 resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} 1454 1660 engines: {node: '>=12.0.0'} ··· 1461 1667 engines: {node: '>= 10.17.0'} 1462 1668 hasBin: true 1463 1669 1670 + fast-deep-equal@3.1.3: 1671 + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1672 + 1464 1673 fast-glob@3.3.3: 1465 1674 resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 1466 1675 engines: {node: '>=8.6.0'} ··· 1471 1680 1472 1681 fastq@1.19.1: 1473 1682 resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 1683 + 1684 + fd-package-json@2.0.0: 1685 + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} 1474 1686 1475 1687 fd-slicer@1.1.0: 1476 1688 resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} ··· 1500 1712 engines: {node: '>=18'} 1501 1713 hasBin: true 1502 1714 1715 + formatly@0.3.0: 1716 + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} 1717 + engines: {node: '>=18.3.0'} 1718 + hasBin: true 1719 + 1503 1720 formdata-node@6.0.3: 1504 1721 resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} 1505 1722 engines: {node: '>= 18'} ··· 1536 1753 get-stream@5.2.0: 1537 1754 resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} 1538 1755 engines: {node: '>=8'} 1756 + 1757 + get-stream@6.0.1: 1758 + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1759 + engines: {node: '>=10'} 1539 1760 1540 1761 giget@2.0.0: 1541 1762 resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} ··· 1589 1810 1590 1811 htmlparser2@10.0.0: 1591 1812 resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} 1813 + 1814 + human-signals@2.1.0: 1815 + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 1816 + engines: {node: '>=10.17.0'} 1592 1817 1593 1818 iconv-lite@0.7.0: 1594 1819 resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} ··· 1701 1926 resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} 1702 1927 engines: {node: '>=0.10.0'} 1703 1928 1929 + is-port-reachable@4.0.0: 1930 + resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} 1931 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1932 + 1704 1933 is-potential-custom-element-name@1.0.1: 1705 1934 resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} 1706 1935 ··· 1711 1940 is-relative@0.1.3: 1712 1941 resolution: {integrity: sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==} 1713 1942 engines: {node: '>=0.10.0'} 1943 + 1944 + is-stream@2.0.1: 1945 + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1946 + engines: {node: '>=8'} 1714 1947 1715 1948 is-unicode-supported@1.3.0: 1716 1949 resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} ··· 1774 2007 1775 2008 js-tokens@9.0.1: 1776 2009 resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} 2010 + 2011 + js-yaml@4.1.1: 2012 + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} 2013 + hasBin: true 1777 2014 1778 2015 json-parse-even-better-errors@3.0.2: 1779 2016 resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} 1780 2017 engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 1781 2018 2019 + json-schema-traverse@1.0.0: 2020 + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 2021 + 1782 2022 json5@2.2.3: 1783 2023 resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 1784 2024 engines: {node: '>=6'} ··· 1793 2033 kleur@3.0.3: 1794 2034 resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} 1795 2035 engines: {node: '>=6'} 2036 + 2037 + knip@5.80.1: 2038 + resolution: {integrity: sha512-aMqGxyoAgLzTd6g3bN7J+Mef0R/WqWKz4zazvKQisprPdszp7X/CHRAPVsVYIkUAIDWCiC/s65JOrva3DwR9yQ==} 2039 + engines: {node: '>=18.18.0'} 2040 + hasBin: true 2041 + peerDependencies: 2042 + '@types/node': '>=18' 2043 + typescript: '>=5.0.4 <7' 1796 2044 1797 2045 ky@1.12.0: 1798 2046 resolution: {integrity: sha512-YRLmSUHCwOJRBMArtqMRLOmO7fewn3yOoui6aB8ERkRVXupa0UiaQaKbIXteMt4jUElhbdqTMsLFHs8APxxUoQ==} ··· 1878 2126 marky@1.3.0: 1879 2127 resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} 1880 2128 2129 + merge-stream@2.0.0: 2130 + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 2131 + 1881 2132 merge2@1.4.1: 1882 2133 resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1883 2134 engines: {node: '>= 8'} ··· 1886 2137 resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 1887 2138 engines: {node: '>=8.6'} 1888 2139 2140 + mime-db@1.33.0: 2141 + resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} 2142 + engines: {node: '>= 0.6'} 2143 + 2144 + mime-db@1.54.0: 2145 + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} 2146 + engines: {node: '>= 0.6'} 2147 + 2148 + mime-types@2.1.18: 2149 + resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} 2150 + engines: {node: '>= 0.6'} 2151 + 1889 2152 mimic-fn@2.1.0: 1890 2153 resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 1891 2154 engines: {node: '>=6'} ··· 1910 2173 1911 2174 mlly@1.8.0: 1912 2175 resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} 2176 + 2177 + ms@2.0.0: 2178 + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} 1913 2179 1914 2180 ms@2.1.3: 1915 2181 resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} ··· 1942 2208 engines: {node: ^18 || >=20} 1943 2209 hasBin: true 1944 2210 2211 + negotiator@0.6.4: 2212 + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} 2213 + engines: {node: '>= 0.6'} 2214 + 1945 2215 node-fetch-native@1.6.7: 1946 2216 resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} 1947 2217 ··· 1956 2226 resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1957 2227 engines: {node: '>=0.10.0'} 1958 2228 2229 + npm-run-path@4.0.1: 2230 + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 2231 + engines: {node: '>=8'} 2232 + 1959 2233 nth-check@2.1.1: 1960 2234 resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} 1961 2235 ··· 1980 2254 on-exit-leak-free@2.1.2: 1981 2255 resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} 1982 2256 engines: {node: '>=14.0.0'} 2257 + 2258 + on-headers@1.1.0: 2259 + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} 2260 + engines: {node: '>= 0.8'} 1983 2261 1984 2262 once@1.4.0: 1985 2263 resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} ··· 2012 2290 resolution: {integrity: sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==} 2013 2291 engines: {node: '>= 0.4.0'} 2014 2292 2293 + oxc-resolver@11.16.2: 2294 + resolution: {integrity: sha512-Uy76u47vwhhF7VAmVY61Srn+ouiOobf45MU9vGct9GD2ARy6hKoqEElyHDB0L+4JOM6VLuZ431KiLwyjI/A21g==} 2295 + 2015 2296 package-json@10.0.1: 2016 2297 resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} 2017 2298 engines: {node: '>=18'} ··· 2032 2313 parse5@6.0.1: 2033 2314 resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} 2034 2315 2316 + path-is-inside@1.0.2: 2317 + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} 2318 + 2319 + path-key@3.1.1: 2320 + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 2321 + engines: {node: '>=8'} 2322 + 2323 + path-to-regexp@3.3.0: 2324 + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} 2325 + 2035 2326 pathe@2.0.3: 2036 2327 resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 2037 2328 ··· 2110 2401 pump@3.0.3: 2111 2402 resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} 2112 2403 2404 + punycode@2.3.1: 2405 + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 2406 + engines: {node: '>=6'} 2407 + 2113 2408 pupa@3.3.0: 2114 2409 resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} 2115 2410 engines: {node: '>=12.20'} ··· 2122 2417 2123 2418 quick-format-unescaped@4.0.4: 2124 2419 resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} 2420 + 2421 + range-parser@1.2.0: 2422 + resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} 2423 + engines: {node: '>= 0.6'} 2125 2424 2126 2425 rc9@2.1.2: 2127 2426 resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} ··· 2145 2444 resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} 2146 2445 engines: {node: '>= 12.13.0'} 2147 2446 2447 + registry-auth-token@3.3.2: 2448 + resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} 2449 + 2148 2450 registry-auth-token@5.1.0: 2149 2451 resolution: {integrity: sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==} 2150 2452 engines: {node: '>=14'} 2151 2453 2454 + registry-url@3.1.0: 2455 + resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} 2456 + engines: {node: '>=0.10.0'} 2457 + 2152 2458 registry-url@6.0.1: 2153 2459 resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} 2154 2460 engines: {node: '>=12'} ··· 2157 2463 resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 2158 2464 engines: {node: '>=0.10.0'} 2159 2465 2466 + require-from-string@2.0.2: 2467 + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 2468 + engines: {node: '>=0.10.0'} 2469 + 2160 2470 restore-cursor@4.0.0: 2161 2471 resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} 2162 2472 engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} ··· 2215 2525 engines: {node: '>=10'} 2216 2526 hasBin: true 2217 2527 2528 + serve-handler@6.1.6: 2529 + resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} 2530 + 2531 + serve@14.2.5: 2532 + resolution: {integrity: sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==} 2533 + engines: {node: '>= 14'} 2534 + hasBin: true 2535 + 2218 2536 set-value@4.1.0: 2219 2537 resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} 2220 2538 engines: {node: '>=11.0'} ··· 2222 2540 setimmediate@1.0.5: 2223 2541 resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} 2224 2542 2543 + shebang-command@2.0.0: 2544 + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 2545 + engines: {node: '>=8'} 2546 + 2547 + shebang-regex@3.0.0: 2548 + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 2549 + engines: {node: '>=8'} 2550 + 2225 2551 shell-quote@1.7.3: 2226 2552 resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} 2227 2553 ··· 2252 2578 slice-ansi@7.1.2: 2253 2579 resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} 2254 2580 engines: {node: '>=18'} 2581 + 2582 + smol-toml@1.6.0: 2583 + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} 2584 + engines: {node: '>= 18'} 2255 2585 2256 2586 sonic-boom@4.2.0: 2257 2587 resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} ··· 2299 2629 resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 2300 2630 engines: {node: '>=8'} 2301 2631 2632 + string-width@5.1.2: 2633 + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 2634 + engines: {node: '>=12'} 2635 + 2302 2636 string-width@7.2.0: 2303 2637 resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} 2304 2638 engines: {node: '>=18'} ··· 2321 2655 resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==} 2322 2656 engines: {node: '>=12'} 2323 2657 2658 + strip-final-newline@2.0.0: 2659 + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 2660 + engines: {node: '>=6'} 2661 + 2324 2662 strip-json-comments@2.0.1: 2325 2663 resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} 2326 2664 engines: {node: '>=0.10.0'} 2327 2665 2328 2666 strip-json-comments@5.0.2: 2329 2667 resolution: {integrity: sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==} 2668 + engines: {node: '>=14.16'} 2669 + 2670 + strip-json-comments@5.0.3: 2671 + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} 2330 2672 engines: {node: '>=14.16'} 2331 2673 2332 2674 strip-literal@3.1.0: ··· 2339 2681 resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 2340 2682 engines: {node: '>=8'} 2341 2683 2684 + supports-color@8.1.1: 2685 + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 2686 + engines: {node: '>=10'} 2687 + 2342 2688 thenify-all@1.6.0: 2343 2689 resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 2344 2690 engines: {node: '>=0.8'} ··· 2382 2728 resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 2383 2729 engines: {node: '>=8.0'} 2384 2730 2731 + tree-kill@1.2.2: 2732 + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 2733 + hasBin: true 2734 + 2385 2735 tslib@2.8.1: 2386 2736 resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 2737 + 2738 + type-fest@2.19.0: 2739 + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} 2740 + engines: {node: '>=12.20'} 2387 2741 2388 2742 type-fest@3.13.1: 2389 2743 resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} ··· 2396 2750 typedarray@0.0.6: 2397 2751 resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} 2398 2752 2753 + typescript@5.9.3: 2754 + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 2755 + engines: {node: '>=14.17'} 2756 + hasBin: true 2757 + 2399 2758 ufo@1.6.1: 2400 2759 resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 2401 2760 ··· 2427 2786 resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} 2428 2787 engines: {node: '>=18.12.0'} 2429 2788 2789 + update-check@1.5.4: 2790 + resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} 2791 + 2430 2792 update-notifier@7.3.1: 2431 2793 resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} 2432 2794 engines: {node: '>=18'} 2433 2795 2796 + uri-js@4.4.1: 2797 + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2798 + 2434 2799 util-deprecate@1.0.2: 2435 2800 resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2436 2801 ··· 2438 2803 resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} 2439 2804 hasBin: true 2440 2805 2806 + vary@1.1.2: 2807 + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 2808 + engines: {node: '>= 0.8'} 2809 + 2441 2810 vite-node@3.2.4: 2442 2811 resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} 2443 2812 engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} ··· 2548 2917 jsdom: 2549 2918 optional: true 2550 2919 2920 + walk-up-path@4.0.0: 2921 + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} 2922 + engines: {node: 20 || >=22} 2923 + 2551 2924 watchpack@2.4.4: 2552 2925 resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} 2553 2926 engines: {node: '>=10.13.0'} ··· 2586 2959 engines: {node: '>=8'} 2587 2960 hasBin: true 2588 2961 2962 + widest-line@4.0.1: 2963 + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} 2964 + engines: {node: '>=12'} 2965 + 2589 2966 widest-line@5.0.0: 2590 2967 resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} 2591 2968 engines: {node: '>=18'} ··· 2601 2978 resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 2602 2979 engines: {node: '>=10'} 2603 2980 2981 + wrap-ansi@8.1.0: 2982 + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 2983 + engines: {node: '>=12'} 2984 + 2604 2985 wrap-ansi@9.0.2: 2605 2986 resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} 2606 2987 engines: {node: '>=18'} ··· 2660 3041 2661 3042 zod@3.25.76: 2662 3043 resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} 3044 + 3045 + zod@4.3.5: 3046 + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} 2663 3047 2664 3048 snapshots: 2665 3049 ··· 2791 3175 split: 1.0.1 2792 3176 transitivePeerDependencies: 2793 3177 - supports-color 3178 + 3179 + '@emnapi/core@1.8.1': 3180 + dependencies: 3181 + '@emnapi/wasi-threads': 1.1.0 3182 + tslib: 2.8.1 3183 + optional: true 3184 + 3185 + '@emnapi/runtime@1.8.1': 3186 + dependencies: 3187 + tslib: 2.8.1 3188 + optional: true 3189 + 3190 + '@emnapi/wasi-threads@1.1.0': 3191 + dependencies: 3192 + tslib: 2.8.1 3193 + optional: true 2794 3194 2795 3195 '@esbuild/aix-ppc64@0.21.5': 2796 3196 optional: true ··· 3178 3578 '@jridgewell/resolve-uri': 3.1.2 3179 3579 '@jridgewell/sourcemap-codec': 1.5.5 3180 3580 3581 + '@napi-rs/wasm-runtime@1.1.1': 3582 + dependencies: 3583 + '@emnapi/core': 1.8.1 3584 + '@emnapi/runtime': 1.8.1 3585 + '@tybys/wasm-util': 0.10.1 3586 + optional: true 3587 + 3181 3588 '@nodelib/fs.scandir@2.1.5': 3182 3589 dependencies: 3183 3590 '@nodelib/fs.stat': 2.0.5 ··· 3189 3596 dependencies: 3190 3597 '@nodelib/fs.scandir': 2.1.5 3191 3598 fastq: 1.19.1 3599 + 3600 + '@oxc-resolver/binding-android-arm-eabi@11.16.2': 3601 + optional: true 3602 + 3603 + '@oxc-resolver/binding-android-arm64@11.16.2': 3604 + optional: true 3605 + 3606 + '@oxc-resolver/binding-darwin-arm64@11.16.2': 3607 + optional: true 3608 + 3609 + '@oxc-resolver/binding-darwin-x64@11.16.2': 3610 + optional: true 3611 + 3612 + '@oxc-resolver/binding-freebsd-x64@11.16.2': 3613 + optional: true 3614 + 3615 + '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.2': 3616 + optional: true 3617 + 3618 + '@oxc-resolver/binding-linux-arm-musleabihf@11.16.2': 3619 + optional: true 3620 + 3621 + '@oxc-resolver/binding-linux-arm64-gnu@11.16.2': 3622 + optional: true 3623 + 3624 + '@oxc-resolver/binding-linux-arm64-musl@11.16.2': 3625 + optional: true 3626 + 3627 + '@oxc-resolver/binding-linux-ppc64-gnu@11.16.2': 3628 + optional: true 3629 + 3630 + '@oxc-resolver/binding-linux-riscv64-gnu@11.16.2': 3631 + optional: true 3632 + 3633 + '@oxc-resolver/binding-linux-riscv64-musl@11.16.2': 3634 + optional: true 3635 + 3636 + '@oxc-resolver/binding-linux-s390x-gnu@11.16.2': 3637 + optional: true 3638 + 3639 + '@oxc-resolver/binding-linux-x64-gnu@11.16.2': 3640 + optional: true 3641 + 3642 + '@oxc-resolver/binding-linux-x64-musl@11.16.2': 3643 + optional: true 3644 + 3645 + '@oxc-resolver/binding-openharmony-arm64@11.16.2': 3646 + optional: true 3647 + 3648 + '@oxc-resolver/binding-wasm32-wasi@11.16.2': 3649 + dependencies: 3650 + '@napi-rs/wasm-runtime': 1.1.1 3651 + optional: true 3652 + 3653 + '@oxc-resolver/binding-win32-arm64-msvc@11.16.2': 3654 + optional: true 3655 + 3656 + '@oxc-resolver/binding-win32-ia32-msvc@11.16.2': 3657 + optional: true 3658 + 3659 + '@oxc-resolver/binding-win32-x64-msvc@11.16.2': 3660 + optional: true 3192 3661 3193 3662 '@playwright/test@1.57.0': 3194 3663 dependencies: ··· 3274 3743 3275 3744 '@standard-schema/spec@1.0.0': {} 3276 3745 3746 + '@tybys/wasm-util@0.10.1': 3747 + dependencies: 3748 + tslib: 2.8.1 3749 + optional: true 3750 + 3277 3751 '@types/chai@5.2.3': 3278 3752 dependencies: 3279 3753 '@types/deep-eql': 4.0.2 ··· 3385 3859 async-mutex: 0.5.0 3386 3860 dequal: 2.0.3 3387 3861 3862 + '@zeit/schemas@2.36.0': {} 3863 + 3388 3864 acorn@8.15.0: {} 3389 3865 3390 3866 adm-zip@0.5.16: {} 3867 + 3868 + ajv@8.12.0: 3869 + dependencies: 3870 + fast-deep-equal: 3.1.3 3871 + json-schema-traverse: 1.0.0 3872 + require-from-string: 2.0.2 3873 + uri-js: 4.4.1 3391 3874 3392 3875 ancestors@0.0.3: {} 3393 3876 ··· 3411 3894 3412 3895 any-promise@1.3.0: {} 3413 3896 3897 + arch@2.2.0: {} 3898 + 3899 + arg@5.0.2: {} 3900 + 3901 + argparse@2.0.1: {} 3902 + 3414 3903 array-differ@4.0.0: {} 3415 3904 3416 3905 array-union@3.0.1: {} ··· 3452 3941 3453 3942 boolbase@1.0.0: {} 3454 3943 3944 + boxen@7.0.0: 3945 + dependencies: 3946 + ansi-align: 3.0.1 3947 + camelcase: 7.0.1 3948 + chalk: 5.6.2 3949 + cli-boxes: 3.0.0 3950 + string-width: 5.1.2 3951 + type-fest: 2.19.0 3952 + widest-line: 4.0.1 3953 + wrap-ansi: 8.1.0 3954 + 3455 3955 boxen@8.0.1: 3456 3956 dependencies: 3457 3957 ansi-align: 3.0.1 ··· 3489 3989 dependencies: 3490 3990 run-applescript: 7.1.0 3491 3991 3992 + bytes@3.0.0: {} 3993 + 3994 + bytes@3.1.2: {} 3995 + 3492 3996 c12@3.3.1(magicast@0.3.5): 3493 3997 dependencies: 3494 3998 chokidar: 4.0.3 ··· 3508 4012 3509 4013 cac@6.7.14: {} 3510 4014 4015 + camelcase@7.0.1: {} 4016 + 3511 4017 camelcase@8.0.0: {} 3512 4018 3513 4019 chai@6.2.2: {} 3514 4020 4021 + chalk-template@0.4.0: 4022 + dependencies: 4023 + chalk: 4.1.2 4024 + 3515 4025 chalk@4.1.2: 3516 4026 dependencies: 3517 4027 ansi-styles: 4.3.0 3518 4028 supports-color: 7.2.0 4029 + 4030 + chalk@5.0.1: {} 3519 4031 3520 4032 chalk@5.6.2: {} 3521 4033 ··· 3568 4080 3569 4081 cli-width@4.1.0: {} 3570 4082 4083 + clipboardy@3.0.0: 4084 + dependencies: 4085 + arch: 2.2.0 4086 + execa: 5.1.1 4087 + is-wsl: 2.2.0 4088 + 3571 4089 cliui@7.0.4: 3572 4090 dependencies: 3573 4091 string-width: 4.2.3 ··· 3596 4114 3597 4115 commander@9.5.0: {} 3598 4116 4117 + compressible@2.0.18: 4118 + dependencies: 4119 + mime-db: 1.54.0 4120 + 4121 + compression@1.8.1: 4122 + dependencies: 4123 + bytes: 3.1.2 4124 + compressible: 2.0.18 4125 + debug: 2.6.9 4126 + negotiator: 0.6.4 4127 + on-headers: 1.1.0 4128 + safe-buffer: 5.2.1 4129 + vary: 1.1.2 4130 + transitivePeerDependencies: 4131 + - supports-color 4132 + 3599 4133 concat-map@0.0.1: {} 3600 4134 3601 4135 concat-stream@1.6.2: ··· 3605 4139 readable-stream: 2.3.8 3606 4140 typedarray: 0.0.6 3607 4141 4142 + concurrently@9.2.1: 4143 + dependencies: 4144 + chalk: 4.1.2 4145 + rxjs: 7.8.2 4146 + shell-quote: 1.8.3 4147 + supports-color: 8.1.1 4148 + tree-kill: 1.2.2 4149 + yargs: 17.7.2 4150 + 3608 4151 confbox@0.1.8: {} 3609 4152 3610 4153 confbox@0.2.2: {} ··· 3623 4166 3624 4167 consola@3.4.2: {} 3625 4168 4169 + content-disposition@0.5.2: {} 4170 + 3626 4171 core-util-is@1.0.3: {} 4172 + 4173 + cross-spawn@7.0.6: 4174 + dependencies: 4175 + path-key: 3.1.1 4176 + shebang-command: 2.0.0 4177 + which: 2.0.2 3627 4178 3628 4179 css-select@5.2.2: 3629 4180 dependencies: ··· 3638 4189 cssom@0.5.0: {} 3639 4190 3640 4191 debounce@1.2.1: {} 4192 + 4193 + debug@2.6.9: 4194 + dependencies: 4195 + ms: 2.0.0 3641 4196 3642 4197 debug@4.3.7: 3643 4198 dependencies: ··· 3727 4282 3728 4283 dotenv@17.2.3: {} 3729 4284 4285 + eastasianwidth@0.2.0: {} 4286 + 3730 4287 ejs@3.1.10: 3731 4288 dependencies: 3732 4289 jake: 10.9.4 ··· 3734 4291 emoji-regex@10.6.0: {} 3735 4292 3736 4293 emoji-regex@8.0.0: {} 4294 + 4295 + emoji-regex@9.2.2: {} 3737 4296 3738 4297 end-of-stream@1.4.5: 3739 4298 dependencies: ··· 3853 4412 3854 4413 eventemitter3@5.0.1: {} 3855 4414 4415 + execa@5.1.1: 4416 + dependencies: 4417 + cross-spawn: 7.0.6 4418 + get-stream: 6.0.1 4419 + human-signals: 2.1.0 4420 + is-stream: 2.0.1 4421 + merge-stream: 2.0.0 4422 + npm-run-path: 4.0.1 4423 + onetime: 5.1.2 4424 + signal-exit: 3.0.7 4425 + strip-final-newline: 2.0.0 4426 + 3856 4427 expect-type@1.3.0: {} 3857 4428 3858 4429 exsolve@1.0.7: {} ··· 3866 4437 '@types/yauzl': 2.10.3 3867 4438 transitivePeerDependencies: 3868 4439 - supports-color 4440 + 4441 + fast-deep-equal@3.1.3: {} 3869 4442 3870 4443 fast-glob@3.3.3: 3871 4444 dependencies: ··· 3881 4454 dependencies: 3882 4455 reusify: 1.1.0 3883 4456 4457 + fd-package-json@2.0.0: 4458 + dependencies: 4459 + walk-up-path: 4.0.0 4460 + 3884 4461 fd-slicer@1.1.0: 3885 4462 dependencies: 3886 4463 pend: 1.2.0 ··· 3907 4484 minimist: 1.2.8 3908 4485 xml2js: 0.6.2 3909 4486 4487 + formatly@0.3.0: 4488 + dependencies: 4489 + fd-package-json: 2.0.0 4490 + 3910 4491 formdata-node@6.0.3: {} 3911 4492 3912 4493 fs-extra@11.3.2: ··· 3939 4520 get-stream@5.2.0: 3940 4521 dependencies: 3941 4522 pump: 3.0.3 4523 + 4524 + get-stream@6.0.1: {} 3942 4525 3943 4526 giget@2.0.0: 3944 4527 dependencies: ··· 3991 4574 domhandler: 5.0.3 3992 4575 domutils: 3.2.2 3993 4576 entities: 6.0.1 4577 + 4578 + human-signals@2.1.0: {} 3994 4579 3995 4580 iconv-lite@0.7.0: 3996 4581 dependencies: ··· 4071 4656 dependencies: 4072 4657 isobject: 3.0.1 4073 4658 4659 + is-port-reachable@4.0.0: {} 4660 + 4074 4661 is-potential-custom-element-name@1.0.1: {} 4075 4662 4076 4663 is-primitive@3.0.1: {} 4077 4664 4078 4665 is-relative@0.1.3: {} 4666 + 4667 + is-stream@2.0.1: {} 4079 4668 4080 4669 is-unicode-supported@1.3.0: {} 4081 4670 ··· 4132 4721 4133 4722 js-tokens@9.0.1: {} 4134 4723 4724 + js-yaml@4.1.1: 4725 + dependencies: 4726 + argparse: 2.0.1 4727 + 4135 4728 json-parse-even-better-errors@3.0.2: {} 4729 + 4730 + json-schema-traverse@1.0.0: {} 4136 4731 4137 4732 json5@2.2.3: {} 4138 4733 ··· 4150 4745 setimmediate: 1.0.5 4151 4746 4152 4747 kleur@3.0.3: {} 4748 + 4749 + knip@5.80.1(@types/node@24.8.1)(typescript@5.9.3): 4750 + dependencies: 4751 + '@nodelib/fs.walk': 1.2.8 4752 + '@types/node': 24.8.1 4753 + fast-glob: 3.3.3 4754 + formatly: 0.3.0 4755 + jiti: 2.6.1 4756 + js-yaml: 4.1.1 4757 + minimist: 1.2.8 4758 + oxc-resolver: 11.16.2 4759 + picocolors: 1.1.1 4760 + picomatch: 4.0.3 4761 + smol-toml: 1.6.0 4762 + strip-json-comments: 5.0.3 4763 + typescript: 5.9.3 4764 + zod: 4.3.5 4153 4765 4154 4766 ky@1.12.0: {} 4155 4767 ··· 4248 4860 many-keys-map@2.0.1: {} 4249 4861 4250 4862 marky@1.3.0: {} 4863 + 4864 + merge-stream@2.0.0: {} 4251 4865 4252 4866 merge2@1.4.1: {} 4253 4867 ··· 4256 4870 braces: 3.0.3 4257 4871 picomatch: 2.3.1 4258 4872 4873 + mime-db@1.33.0: {} 4874 + 4875 + mime-db@1.54.0: {} 4876 + 4877 + mime-types@2.1.18: 4878 + dependencies: 4879 + mime-db: 1.33.0 4880 + 4259 4881 mimic-fn@2.1.0: {} 4260 4882 4261 4883 mimic-function@5.0.1: {} ··· 4281 4903 pkg-types: 1.3.1 4282 4904 ufo: 1.6.1 4283 4905 4906 + ms@2.0.0: {} 4907 + 4284 4908 ms@2.1.3: {} 4285 4909 4286 4910 multiformats@9.9.0: {} ··· 4305 4929 nanoid@3.3.11: {} 4306 4930 4307 4931 nanoid@5.1.6: {} 4932 + 4933 + negotiator@0.6.4: {} 4308 4934 4309 4935 node-fetch-native@1.6.7: {} 4310 4936 ··· 4321 4947 4322 4948 normalize-path@3.0.0: {} 4323 4949 4950 + npm-run-path@4.0.1: 4951 + dependencies: 4952 + path-key: 3.1.1 4953 + 4324 4954 nth-check@2.1.1: 4325 4955 dependencies: 4326 4956 boolbase: 1.0.0 ··· 4346 4976 ohash@2.0.11: {} 4347 4977 4348 4978 on-exit-leak-free@2.1.2: {} 4979 + 4980 + on-headers@1.1.0: {} 4349 4981 4350 4982 once@1.4.0: 4351 4983 dependencies: ··· 4398 5030 4399 5031 os-shim@0.1.3: {} 4400 5032 5033 + oxc-resolver@11.16.2: 5034 + optionalDependencies: 5035 + '@oxc-resolver/binding-android-arm-eabi': 11.16.2 5036 + '@oxc-resolver/binding-android-arm64': 11.16.2 5037 + '@oxc-resolver/binding-darwin-arm64': 11.16.2 5038 + '@oxc-resolver/binding-darwin-x64': 11.16.2 5039 + '@oxc-resolver/binding-freebsd-x64': 11.16.2 5040 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.16.2 5041 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.16.2 5042 + '@oxc-resolver/binding-linux-arm64-gnu': 11.16.2 5043 + '@oxc-resolver/binding-linux-arm64-musl': 11.16.2 5044 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.16.2 5045 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.16.2 5046 + '@oxc-resolver/binding-linux-riscv64-musl': 11.16.2 5047 + '@oxc-resolver/binding-linux-s390x-gnu': 11.16.2 5048 + '@oxc-resolver/binding-linux-x64-gnu': 11.16.2 5049 + '@oxc-resolver/binding-linux-x64-musl': 11.16.2 5050 + '@oxc-resolver/binding-openharmony-arm64': 11.16.2 5051 + '@oxc-resolver/binding-wasm32-wasi': 11.16.2 5052 + '@oxc-resolver/binding-win32-arm64-msvc': 11.16.2 5053 + '@oxc-resolver/binding-win32-ia32-msvc': 11.16.2 5054 + '@oxc-resolver/binding-win32-x64-msvc': 11.16.2 5055 + 4401 5056 package-json@10.0.1: 4402 5057 dependencies: 4403 5058 ky: 1.12.0 ··· 4422 5077 parse5@5.1.1: {} 4423 5078 4424 5079 parse5@6.0.1: {} 5080 + 5081 + path-is-inside@1.0.2: {} 5082 + 5083 + path-key@3.1.1: {} 5084 + 5085 + path-to-regexp@3.3.0: {} 4425 5086 4426 5087 pathe@2.0.3: {} 4427 5088 ··· 4523 5184 end-of-stream: 1.4.5 4524 5185 once: 1.4.0 4525 5186 5187 + punycode@2.3.1: {} 5188 + 4526 5189 pupa@3.3.0: 4527 5190 dependencies: 4528 5191 escape-goat: 4.0.0 ··· 4532 5195 queue-microtask@1.2.3: {} 4533 5196 4534 5197 quick-format-unescaped@4.0.4: {} 5198 + 5199 + range-parser@1.2.0: {} 4535 5200 4536 5201 rc9@2.1.2: 4537 5202 dependencies: ··· 4565 5230 4566 5231 real-require@0.2.0: {} 4567 5232 5233 + registry-auth-token@3.3.2: 5234 + dependencies: 5235 + rc: 1.2.8 5236 + safe-buffer: 5.2.1 5237 + 4568 5238 registry-auth-token@5.1.0: 4569 5239 dependencies: 4570 5240 '@pnpm/npm-conf': 2.3.1 4571 5241 5242 + registry-url@3.1.0: 5243 + dependencies: 5244 + rc: 1.2.8 5245 + 4572 5246 registry-url@6.0.1: 4573 5247 dependencies: 4574 5248 rc: 1.2.8 4575 5249 4576 5250 require-directory@2.1.1: {} 5251 + 5252 + require-from-string@2.0.2: {} 4577 5253 4578 5254 restore-cursor@4.0.0: 4579 5255 dependencies: ··· 4643 5319 4644 5320 semver@7.7.3: {} 4645 5321 5322 + serve-handler@6.1.6: 5323 + dependencies: 5324 + bytes: 3.0.0 5325 + content-disposition: 0.5.2 5326 + mime-types: 2.1.18 5327 + minimatch: 3.1.2 5328 + path-is-inside: 1.0.2 5329 + path-to-regexp: 3.3.0 5330 + range-parser: 1.2.0 5331 + 5332 + serve@14.2.5: 5333 + dependencies: 5334 + '@zeit/schemas': 2.36.0 5335 + ajv: 8.12.0 5336 + arg: 5.0.2 5337 + boxen: 7.0.0 5338 + chalk: 5.0.1 5339 + chalk-template: 0.4.0 5340 + clipboardy: 3.0.0 5341 + compression: 1.8.1 5342 + is-port-reachable: 4.0.0 5343 + serve-handler: 6.1.6 5344 + update-check: 1.5.4 5345 + transitivePeerDependencies: 5346 + - supports-color 5347 + 4646 5348 set-value@4.1.0: 4647 5349 dependencies: 4648 5350 is-plain-object: 2.0.4 4649 5351 is-primitive: 3.0.1 4650 5352 4651 5353 setimmediate@1.0.5: {} 5354 + 5355 + shebang-command@2.0.0: 5356 + dependencies: 5357 + shebang-regex: 3.0.0 5358 + 5359 + shebang-regex@3.0.0: {} 4652 5360 4653 5361 shell-quote@1.7.3: {} 4654 5362 ··· 4674 5382 ansi-styles: 6.2.3 4675 5383 is-fullwidth-code-point: 5.1.0 4676 5384 5385 + smol-toml@1.6.0: {} 5386 + 4677 5387 sonic-boom@4.2.0: 4678 5388 dependencies: 4679 5389 atomic-sleep: 1.0.0 ··· 4716 5426 is-fullwidth-code-point: 3.0.0 4717 5427 strip-ansi: 6.0.1 4718 5428 5429 + string-width@5.1.2: 5430 + dependencies: 5431 + eastasianwidth: 0.2.0 5432 + emoji-regex: 9.2.2 5433 + strip-ansi: 7.1.2 5434 + 4719 5435 string-width@7.2.0: 4720 5436 dependencies: 4721 5437 emoji-regex: 10.6.0 ··· 4740 5456 4741 5457 strip-bom@5.0.0: {} 4742 5458 5459 + strip-final-newline@2.0.0: {} 5460 + 4743 5461 strip-json-comments@2.0.1: {} 4744 5462 4745 5463 strip-json-comments@5.0.2: {} 5464 + 5465 + strip-json-comments@5.0.3: {} 4746 5466 4747 5467 strip-literal@3.1.0: 4748 5468 dependencies: ··· 4754 5474 dependencies: 4755 5475 has-flag: 4.0.0 4756 5476 5477 + supports-color@8.1.1: 5478 + dependencies: 5479 + has-flag: 4.0.0 5480 + 4757 5481 thenify-all@1.6.0: 4758 5482 dependencies: 4759 5483 thenify: 3.3.1 ··· 4788 5512 to-regex-range@5.0.1: 4789 5513 dependencies: 4790 5514 is-number: 7.0.0 5515 + 5516 + tree-kill@1.2.2: {} 4791 5517 4792 5518 tslib@2.8.1: {} 4793 5519 5520 + type-fest@2.19.0: {} 5521 + 4794 5522 type-fest@3.13.1: {} 4795 5523 4796 5524 type-fest@4.41.0: {} 4797 5525 4798 5526 typedarray@0.0.6: {} 5527 + 5528 + typescript@5.9.3: {} 4799 5529 4800 5530 ufo@1.6.1: {} 4801 5531 ··· 4840 5570 picomatch: 4.0.3 4841 5571 webpack-virtual-modules: 0.6.2 4842 5572 5573 + update-check@1.5.4: 5574 + dependencies: 5575 + registry-auth-token: 3.3.2 5576 + registry-url: 3.1.0 5577 + 4843 5578 update-notifier@7.3.1: 4844 5579 dependencies: 4845 5580 boxen: 8.0.1 ··· 4853 5588 semver: 7.7.3 4854 5589 xdg-basedir: 5.1.0 4855 5590 5591 + uri-js@4.4.1: 5592 + dependencies: 5593 + punycode: 2.3.1 5594 + 4856 5595 util-deprecate@1.0.2: {} 4857 5596 4858 5597 uuid@8.3.2: {} 5598 + 5599 + vary@1.1.2: {} 4859 5600 4860 5601 vite-node@3.2.4(@types/node@24.8.1): 4861 5602 dependencies: ··· 4935 5676 - tsx 4936 5677 - yaml 4937 5678 5679 + walk-up-path@4.0.0: {} 5680 + 4938 5681 watchpack@2.4.4: 4939 5682 dependencies: 4940 5683 glob-to-regexp: 0.4.1 ··· 4991 5734 siginfo: 2.0.0 4992 5735 stackback: 0.0.2 4993 5736 5737 + widest-line@4.0.1: 5738 + dependencies: 5739 + string-width: 5.1.2 5740 + 4994 5741 widest-line@5.0.0: 4995 5742 dependencies: 4996 5743 string-width: 7.2.0 ··· 5008 5755 ansi-styles: 4.3.0 5009 5756 string-width: 4.2.3 5010 5757 strip-ansi: 6.0.1 5758 + 5759 + wrap-ansi@8.1.0: 5760 + dependencies: 5761 + ansi-styles: 6.2.3 5762 + string-width: 5.1.2 5763 + strip-ansi: 7.1.2 5011 5764 5012 5765 wrap-ansi@9.0.2: 5013 5766 dependencies: ··· 5129 5882 jszip: 3.10.1 5130 5883 5131 5884 zod@3.25.76: {} 5885 + 5886 + zod@4.3.5: {}
+10
proxy/package.json
··· 1 + { 2 + "name": "seams-proxy", 3 + "private": true, 4 + "scripts": { 5 + "postinstall": "mkdir -p dist && cp node_modules/@webrecorder/wabac/dist/sw.js dist/sw.js" 6 + }, 7 + "dependencies": { 8 + "@webrecorder/wabac": "^2.20.0" 9 + } 10 + }
+159
proxy/src/styles.css
··· 1 + /* Seams Proxy Styles */ 2 + 3 + :root { 4 + --forest-green: #2d5016; 5 + --forest-green-hover: #3d6b1e; 6 + --forest-green-light: #4a7c28; 7 + } 8 + 9 + html, body { 10 + height: 100%; 11 + margin: 0; 12 + padding: 0; 13 + } 14 + 15 + body { 16 + display: flex; 17 + flex-direction: column; 18 + } 19 + 20 + /* Header */ 21 + #header { 22 + padding: 8px; 23 + background: #f0f0f0; 24 + border-bottom: 1px solid #ccc; 25 + font-family: system-ui, sans-serif; 26 + font-size: 12px; 27 + display: flex; 28 + gap: 8px; 29 + align-items: center; 30 + } 31 + 32 + #header input { 33 + width: 400px; 34 + padding: 6px 8px; 35 + border: 1px solid #ccc; 36 + border-radius: 4px; 37 + font-size: 13px; 38 + } 39 + 40 + #header input:focus { 41 + outline: none; 42 + border-color: var(--forest-green); 43 + } 44 + 45 + #header button { 46 + padding: 6px 16px; 47 + background: var(--forest-green); 48 + color: white; 49 + border: none; 50 + border-radius: 4px; 51 + cursor: pointer; 52 + font-size: 13px; 53 + font-weight: 500; 54 + } 55 + 56 + #header button:hover { 57 + background: var(--forest-green-hover); 58 + } 59 + 60 + /* Main container */ 61 + #main-container { 62 + flex: 1; 63 + display: flex; 64 + position: relative; 65 + overflow: hidden; 66 + } 67 + 68 + /* Content iframe */ 69 + #content { 70 + flex: 1; 71 + width: 100%; 72 + height: 100%; 73 + border: none; 74 + transition: margin-right 0.3s ease; 75 + } 76 + 77 + #content.sidebar-open { 78 + margin-right: 400px; 79 + } 80 + 81 + /* Sidebar */ 82 + #sidebar-container { 83 + position: absolute; 84 + top: 0; 85 + right: 0; 86 + width: 400px; 87 + height: 100%; 88 + border-left: 1px solid #ccc; 89 + background: white; 90 + box-shadow: -2px 0 8px rgba(0,0,0,0.1); 91 + transform: translateX(0); 92 + transition: transform 0.3s ease; 93 + z-index: 100; 94 + overflow-y: auto; 95 + } 96 + 97 + #sidebar-container.hidden { 98 + transform: translateX(100%); 99 + } 100 + 101 + /* Toggle button */ 102 + #toggle-btn { 103 + position: absolute; 104 + top: 20px; 105 + right: 20px; 106 + width: 36px; 107 + height: 36px; 108 + border-radius: 50%; 109 + background: var(--forest-green); 110 + color: white; 111 + border: none; 112 + cursor: pointer; 113 + font-size: 14px; 114 + font-weight: bold; 115 + box-shadow: 0 2px 6px rgba(0,0,0,0.25); 116 + z-index: 101; 117 + transition: right 0.3s ease, background 0.2s ease; 118 + display: flex; 119 + align-items: center; 120 + justify-content: center; 121 + } 122 + 123 + #toggle-btn:hover { 124 + background: var(--forest-green-hover); 125 + } 126 + 127 + #toggle-btn.sidebar-open { 128 + right: 420px; 129 + } 130 + 131 + /* Loading state */ 132 + .loading { 133 + display: flex; 134 + align-items: center; 135 + justify-content: center; 136 + height: 100%; 137 + font-family: system-ui, sans-serif; 138 + color: #666; 139 + } 140 + 141 + /* Mobile styles */ 142 + @media (max-width: 768px) { 143 + #header input { 144 + flex: 1; 145 + width: auto; 146 + } 147 + 148 + #sidebar-container { 149 + width: 100%; 150 + } 151 + 152 + #content.sidebar-open { 153 + margin-right: 0; 154 + } 155 + 156 + #toggle-btn.sidebar-open { 157 + right: 20px; 158 + } 159 + }
-10
scripts/mac-deploy-proxy.sh
··· 1 - #!/usr/bin/env bash 2 - set -e 3 - 4 - CONFIG_FILE="fly.proxy.toml" 5 - 6 - echo "🚀 Deploying proxy to Fly.io (remote build)..." 7 - flyctl deploy --config $CONFIG_FILE --remote-only 8 - 9 - echo "✅ Proxy deployment complete!" 10 - echo "🌐 Visit: https://sure.seams.so"
+53
scripts/postbuild-proxy.sh
··· 1 + #!/bin/bash 2 + # Post-build script for proxy 3 + # 1. Flattens nested HTML output from vite 4 + # 2. Copies source files (index.html, loadwabac.js, client-metadata.json) 5 + 6 + set -e # Exit on any error 7 + 8 + OUT_DIR="proxy/dist" 9 + SRC_DIR="proxy/src" 10 + NESTED_DIR="$OUT_DIR/proxy/html" 11 + 12 + # Verify output directory exists 13 + if [ ! -d "$OUT_DIR" ]; then 14 + echo "ERROR: Output directory $OUT_DIR does not exist" 15 + exit 1 16 + fi 17 + 18 + # Move HTML files from nested vite output to root 19 + if [ -d "$NESTED_DIR" ]; then 20 + mv "$NESTED_DIR"/*.html "$OUT_DIR/" || { echo "ERROR: Failed to move HTML files"; exit 1; } 21 + rm -rf "$OUT_DIR/proxy" 22 + echo "Flattened HTML files" 23 + fi 24 + 25 + # Verify source files exist before copying 26 + for file in index.html loadwabac.js client-metadata.json styles.css; do 27 + if [ ! -f "$SRC_DIR/$file" ]; then 28 + echo "ERROR: Required source file $SRC_DIR/$file not found" 29 + exit 1 30 + fi 31 + done 32 + 33 + # Copy source files with error checking 34 + cp "$SRC_DIR/index.html" "$OUT_DIR/" || { echo "ERROR: Failed to copy index.html"; exit 1; } 35 + cp "$SRC_DIR/loadwabac.js" "$OUT_DIR/" || { echo "ERROR: Failed to copy loadwabac.js"; exit 1; } 36 + cp "$SRC_DIR/client-metadata.json" "$OUT_DIR/" || { echo "ERROR: Failed to copy client-metadata.json"; exit 1; } 37 + cp "$SRC_DIR/styles.css" "$OUT_DIR/" || { echo "ERROR: Failed to copy styles.css"; exit 1; } 38 + echo "Copied source files from $SRC_DIR" 39 + 40 + # Copy wabac.js service worker 41 + WABAC_SW="proxy/node_modules/@webrecorder/wabac/dist/sw.js" 42 + if [ -f "$WABAC_SW" ]; then 43 + cp "$WABAC_SW" "$OUT_DIR/" || { echo "ERROR: Failed to copy wabac.js service worker"; exit 1; } 44 + echo "Copied wabac.js service worker" 45 + else 46 + echo "ERROR: wabac.js sw.js not found at $WABAC_SW" 47 + echo "Run 'cd proxy && npm install' to install dependencies" 48 + exit 1 49 + fi 50 + 51 + echo "" 52 + echo "Build complete. Files in $OUT_DIR/:" 53 + ls -la "$OUT_DIR"/*.html "$OUT_DIR"/*.js "$OUT_DIR"/*.json "$OUT_DIR"/*.css 2>/dev/null
-72
scripts/postbuild-sure-client.js
··· 1 - #!/usr/bin/env node 2 - /** 3 - * Post-build script for sure-client-proxy 4 - * Cross-platform alternative to postbuild-sure-client.sh 5 - * 1. Flattens nested HTML output from vite 6 - * 2. Copies source files (index.html, loadwabac.js, client-metadata.json) 7 - */ 8 - 9 - const fs = require('fs'); 10 - const path = require('path'); 11 - 12 - const OUT_DIR = 'sure-client-proxy/dist'; 13 - const SRC_DIR = 'sure-client-proxy/src'; 14 - const NESTED_DIR = path.join(OUT_DIR, 'sure-client-proxy/html'); 15 - 16 - function copyFile(src, dest) { 17 - fs.copyFileSync(src, dest); 18 - console.log(`Copied: ${src} -> ${dest}`); 19 - } 20 - 21 - function main() { 22 - // Verify output directory exists 23 - if (!fs.existsSync(OUT_DIR)) { 24 - console.error(`ERROR: Output directory ${OUT_DIR} does not exist`); 25 - process.exit(1); 26 - } 27 - 28 - // Move HTML files from nested vite output to root 29 - if (fs.existsSync(NESTED_DIR)) { 30 - const htmlFiles = fs.readdirSync(NESTED_DIR).filter(f => f.endsWith('.html')); 31 - for (const file of htmlFiles) { 32 - fs.renameSync(path.join(NESTED_DIR, file), path.join(OUT_DIR, file)); 33 - } 34 - // Remove empty nested directories 35 - fs.rmSync(path.join(OUT_DIR, 'sure-client-proxy'), { recursive: true }); 36 - console.log('Flattened HTML files'); 37 - } 38 - 39 - // Copy source files 40 - const sourceFiles = ['index.html', 'loadwabac.js', 'client-metadata.json']; 41 - for (const file of sourceFiles) { 42 - const srcPath = path.join(SRC_DIR, file); 43 - if (!fs.existsSync(srcPath)) { 44 - console.error(`ERROR: Required source file ${srcPath} not found`); 45 - process.exit(1); 46 - } 47 - copyFile(srcPath, path.join(OUT_DIR, file)); 48 - } 49 - 50 - // Copy wabac.js service worker 51 - const wabacSW = 'sure-client-proxy/node_modules/@webrecorder/wabac/dist/sw.js'; 52 - if (fs.existsSync(wabacSW)) { 53 - copyFile(wabacSW, path.join(OUT_DIR, 'sw.js')); 54 - console.log('Copied wabac.js service worker'); 55 - } else { 56 - console.error(`ERROR: wabac.js sw.js not found at ${wabacSW}`); 57 - console.error("Run 'cd sure-client-proxy && npm install' to install dependencies"); 58 - process.exit(1); 59 - } 60 - 61 - console.log(''); 62 - console.log(`Build complete. Files in ${OUT_DIR}/:`); 63 - const files = fs.readdirSync(OUT_DIR).filter(f => 64 - f.endsWith('.html') || f.endsWith('.js') || f.endsWith('.json') 65 - ); 66 - for (const file of files) { 67 - const stats = fs.statSync(path.join(OUT_DIR, file)); 68 - console.log(` ${file} (${stats.size} bytes)`); 69 - } 70 - } 71 - 72 - main();
-52
scripts/postbuild-sure-client.sh
··· 1 - #!/bin/bash 2 - # Post-build script for sure-client-proxy 3 - # 1. Flattens nested HTML output from vite 4 - # 2. Copies source files (index.html, loadwabac.js, client-metadata.json) 5 - 6 - set -e # Exit on any error 7 - 8 - OUT_DIR="sure-client-proxy/dist" 9 - SRC_DIR="sure-client-proxy/src" 10 - NESTED_DIR="$OUT_DIR/sure-client-proxy/html" 11 - 12 - # Verify output directory exists 13 - if [ ! -d "$OUT_DIR" ]; then 14 - echo "ERROR: Output directory $OUT_DIR does not exist" 15 - exit 1 16 - fi 17 - 18 - # Move HTML files from nested vite output to root 19 - if [ -d "$NESTED_DIR" ]; then 20 - mv "$NESTED_DIR"/*.html "$OUT_DIR/" || { echo "ERROR: Failed to move HTML files"; exit 1; } 21 - rm -rf "$OUT_DIR/sure-client-proxy" 22 - echo "Flattened HTML files" 23 - fi 24 - 25 - # Verify source files exist before copying 26 - for file in index.html loadwabac.js client-metadata.json; do 27 - if [ ! -f "$SRC_DIR/$file" ]; then 28 - echo "ERROR: Required source file $SRC_DIR/$file not found" 29 - exit 1 30 - fi 31 - done 32 - 33 - # Copy source files with error checking 34 - cp "$SRC_DIR/index.html" "$OUT_DIR/" || { echo "ERROR: Failed to copy index.html"; exit 1; } 35 - cp "$SRC_DIR/loadwabac.js" "$OUT_DIR/" || { echo "ERROR: Failed to copy loadwabac.js"; exit 1; } 36 - cp "$SRC_DIR/client-metadata.json" "$OUT_DIR/" || { echo "ERROR: Failed to copy client-metadata.json"; exit 1; } 37 - echo "Copied source files from $SRC_DIR" 38 - 39 - # Copy wabac.js service worker 40 - WABAC_SW="sure-client-proxy/node_modules/@webrecorder/wabac/dist/sw.js" 41 - if [ -f "$WABAC_SW" ]; then 42 - cp "$WABAC_SW" "$OUT_DIR/" || { echo "ERROR: Failed to copy wabac.js service worker"; exit 1; } 43 - echo "Copied wabac.js service worker" 44 - else 45 - echo "ERROR: wabac.js sw.js not found at $WABAC_SW" 46 - echo "Run 'cd sure-client-proxy && npm install' to install dependencies" 47 - exit 1 48 - fi 49 - 50 - echo "" 51 - echo "Build complete. Files in $OUT_DIR/:" 52 - ls -la "$OUT_DIR"/*.html "$OUT_DIR"/*.js "$OUT_DIR"/*.json 2>/dev/null
-31
scripts/postbuild-via.sh
··· 1 - #!/usr/bin/env bash 2 - # Post-build script for via proxy - fixes HTML paths and copies to correct location 3 - 4 - set -e 5 - 6 - echo "📝 Post-processing via build..." 7 - 8 - # Copy BUILT HTML files from the nested output directory to static root 9 - # Vite outputs to proxy/static/proxy/via-html/ because of input structure 10 - cp proxy/static/proxy/via-html/*.html proxy/static/ 11 - 12 - # Clean up the nested directory structure created by Vite 13 - rm -rf proxy/static/proxy 14 - 15 - # Copy CSS and font files from landing to static root 16 - echo "🎨 Copying shared assets from landing..." 17 - cp landing/landing.css proxy/static/ 18 - cp landing/fonts.css proxy/static/ 19 - cp landing/favicon.ico proxy/static/ 20 - # cp landing/landing.js proxy/static/ 21 - mkdir -p proxy/static/fonts 22 - cp landing/fonts/* proxy/static/fonts/ 23 - 24 - # Copy client-metadata.json from landing to static root (proxy shares the same client ID) 25 - cp landing/oauth/client-metadata.json proxy/static/ 26 - 27 - # Fix asset paths in HTML files (add /static prefix) 28 - # sed -i 's|src="/seams-|src="/static/seams-|g' proxy/static/*.html 29 - # sed -i 's|href="/assets/|href="/static/assets/|g' proxy/static/*.html 30 - 31 - echo "✅ Via build post-processing complete"
-60
scripts/start-via.sh
··· 1 - #!/usr/bin/env bash 2 - # Start via proxy development servers 3 - 4 - set -e 5 - 6 - echo "🔨 Building via client scripts (watch mode)..." 7 - 8 - # Export development OAuth configuration for localhost 9 - # Note: Use 127.0.0.1 for redirect_uri as required by RFC 8252 10 - # The redirect_uri in the client_id must match the actual redirect_uri used. 11 - export VITE_OAUTH_CLIENT_ID="http://localhost?redirect_uri=http%3A%2F%2F127.0.0.1%3A8082%2Foauth%2Fcallback&scope=atproto" 12 - export VITE_OAUTH_REDIRECT_URI="http://127.0.0.1:8082/oauth/callback" 13 - export VITE_OAUTH_SCOPE="atproto" 14 - export BACKEND_URL="http://localhost:8080" 15 - 16 - pnpm dev:via & 17 - BUILD_PID=$! 18 - 19 - # Wait for initial build 20 - sleep 2 21 - 22 - echo "" 23 - echo "🚀 Starting via proxy servers..." 24 - echo "" 25 - 26 - # Kill any existing processes on these ports 27 - lsof -ti:8081 | xargs kill -9 2>/dev/null || true 28 - lsof -ti:8082 | xargs kill -9 2>/dev/null || true 29 - 30 - # Ensure LD_LIBRARY_PATH is set for pywb (needed for gevent/greenlet) 31 - # This should already be set by the nix shell, but we make sure here 32 - if [ -z "$LD_LIBRARY_PATH" ]; then 33 - echo "⚠️ LD_LIBRARY_PATH not set. Run this from nix shell!" 34 - exit 1 35 - fi 36 - 37 - # Start pywb in background (must run from proxy directory) 38 - echo "📦 Starting pywb on port 8081..." 39 - (cd proxy && LD_LIBRARY_PATH="$LD_LIBRARY_PATH" wayback -p 8081) & 40 - PYWB_PID=$! 41 - 42 - # Wait for pywb to start 43 - sleep 2 44 - 45 - # Start Caddy in foreground 46 - echo "🌐 Starting Caddy on port 8082..." 47 - echo "" 48 - echo "✅ Via proxy ready at http://localhost:8082" 49 - echo "" 50 - echo "Press Ctrl+C to stop all services" 51 - echo "" 52 - 53 - # Trap to kill background processes on exit 54 - trap "kill $BUILD_PID $PYWB_PID 2>/dev/null || true" EXIT 55 - 56 - # Run Caddy (blocks) 57 - caddy run 58 - 59 - # Cleanup 60 - kill $BUILD_PID $PYWB_PID 2>/dev/null || true
sure-client-proxy/.gitignore proxy/.gitignore
sure-client-proxy/Caddyfile proxy/Caddyfile
+4 -4
sure-client-proxy/README.md proxy/README.md
··· 1 - # Seams Client-Side Proxy 1 + # Seams Web Proxy 2 2 3 - A client-side web proxy using wabac.js, replacing the server-side pywb proxy. 3 + A client-side web proxy using wabac.js for annotating any webpage without installing an extension. 4 4 5 5 ## Architecture 6 6 7 - Instead of fetching pages server-side (pywb), this approach uses: 7 + This approach uses: 8 8 9 9 1. **CORS Proxy** (`cors-proxy/`) - Node.js server that adds CORS headers with SSRF protection 10 10 2. **wabac.js Service Worker** - Intercepts requests in the browser and routes through CORS proxy ··· 43 43 ## Directory Structure 44 44 45 45 ``` 46 - sure-client-proxy/ 46 + proxy/ 47 47 ├── cors-proxy/ 48 48 │ ├── index.ts # Hono-based CORS proxy server 49 49 │ ├── package.json
sure-client-proxy/cors-proxy/index.ts proxy/cors-proxy/index.ts
sure-client-proxy/cors-proxy/package-lock.json proxy/cors-proxy/package-lock.json
sure-client-proxy/cors-proxy/package.json proxy/cors-proxy/package.json
sure-client-proxy/cors-proxy/tsconfig.json proxy/cors-proxy/tsconfig.json
+1 -1
sure-client-proxy/html/oauth-callback.html proxy/html/oauth-callback.html
··· 72 72 <h2>Connecting...</h2> 73 73 <p id="status">Completing authentication</p> 74 74 </div> 75 - <script type="module" src="../../entrypoints/via-client/oauth-callback.ts"></script> 75 + <script type="module" src="../src/oauth-callback.ts"></script> 76 76 </body> 77 77 </html>
+1 -1
sure-client-proxy/html/seams-shell.html proxy/html/seams-shell.html
··· 7 7 </head> 8 8 <body> 9 9 <!-- Shell script - manages BackgroundWorker and message routing --> 10 - <script type="module" src="../../entrypoints/via-client/shell.ts"></script> 10 + <script type="module" src="../src/shell.ts"></script> 11 11 </body> 12 12 </html>
+2 -2
sure-client-proxy/package-lock.json proxy/package-lock.json
··· 1 1 { 2 - "name": "sure-client-proxy", 2 + "name": "seams-proxy", 3 3 "lockfileVersion": 3, 4 4 "requires": true, 5 5 "packages": { 6 6 "": { 7 - "name": "sure-client-proxy", 7 + "name": "seams-proxy", 8 8 "hasInstallScript": true, 9 9 "dependencies": { 10 10 "@webrecorder/wabac": "^2.20.0"
-20
sure-client-proxy/package.json
··· 1 - { 2 - "name": "sure-client-proxy", 3 - "private": true, 4 - "scripts": { 5 - "postinstall": "mkdir -p dist && cp node_modules/@webrecorder/wabac/dist/sw.js dist/sw.js", 6 - "dev": "npm run build:client && concurrently \"npm run dev:cors\" \"npm run dev:static\"", 7 - "dev:cors": "cd cors-proxy && npm run dev", 8 - "dev:static": "npx serve dist -l 8081", 9 - "build": "npm run build:client && npm run build:cors", 10 - "build:cors": "cd cors-proxy && npm run build", 11 - "build:client": "cd .. && NODE_ENV=development vite build --config vite.sure-client.config.ts && NODE_ENV=development vite build --config vite.sure-client-inject.config.ts && bash scripts/postbuild-sure-client.sh" 12 - }, 13 - "dependencies": { 14 - "@webrecorder/wabac": "^2.20.0" 15 - }, 16 - "devDependencies": { 17 - "concurrently": "^8.0.0", 18 - "serve": "^14.0.0" 19 - } 20 - }
sure-client-proxy/src/client-metadata.json proxy/src/client-metadata.json
+4 -104
sure-client-proxy/src/index.html proxy/src/index.html
··· 4 4 <title>Seams Proxy</title> 5 5 <meta charset="utf-8"> 6 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 - <style> 8 - html, body { 9 - height: 100%; 10 - margin: 0; 11 - padding: 0; 12 - } 13 - body { 14 - display: flex; 15 - flex-direction: column; 16 - } 17 - #header { 18 - padding: 8px; 19 - background: #f0f0f0; 20 - border-bottom: 1px solid #ccc; 21 - font-family: system-ui, sans-serif; 22 - font-size: 12px; 23 - } 24 - #header input { 25 - width: 400px; 26 - padding: 4px; 27 - } 28 - #main-container { 29 - flex: 1; 30 - display: flex; 31 - position: relative; 32 - overflow: hidden; 33 - } 34 - #content { 35 - flex: 1; 36 - width: 100%; 37 - height: 100%; 38 - border: none; 39 - transition: margin-right 0.3s ease; 40 - } 41 - #content.sidebar-open { 42 - margin-right: 400px; 43 - } 44 - #sidebar-container { 45 - position: absolute; 46 - top: 0; 47 - right: 0; 48 - width: 400px; 49 - height: 100%; 50 - border-left: 1px solid #ccc; 51 - background: white; 52 - box-shadow: -2px 0 8px rgba(0,0,0,0.1); 53 - transform: translateX(0); 54 - transition: transform 0.3s ease; 55 - z-index: 100; 56 - overflow-y: auto; 57 - } 58 - #sidebar-container.hidden { 59 - transform: translateX(100%); 60 - } 61 - #toggle-btn { 62 - position: absolute; 63 - bottom: 20px; 64 - right: 20px; 65 - width: 48px; 66 - height: 48px; 67 - border-radius: 50%; 68 - background: #3b82f6; 69 - color: white; 70 - border: none; 71 - cursor: pointer; 72 - font-size: 18px; 73 - font-weight: bold; 74 - box-shadow: 0 2px 8px rgba(0,0,0,0.3); 75 - z-index: 101; 76 - transition: right 0.3s ease, background 0.2s ease; 77 - display: flex; 78 - align-items: center; 79 - justify-content: center; 80 - } 81 - #toggle-btn:hover { 82 - background: #2563eb; 83 - } 84 - #toggle-btn.sidebar-open { 85 - right: 420px; 86 - } 87 - .loading { 88 - display: flex; 89 - align-items: center; 90 - justify-content: center; 91 - height: 100%; 92 - font-family: system-ui, sans-serif; 93 - color: #666; 94 - } 95 - /* Mobile styles */ 96 - @media (max-width: 768px) { 97 - #sidebar-container { 98 - width: 100%; 99 - } 100 - #content.sidebar-open { 101 - margin-right: 0; 102 - } 103 - #toggle-btn.sidebar-open { 104 - right: 20px; 105 - } 106 - } 107 - </style> 7 + <link rel="stylesheet" href="./styles.css"> 108 8 <script src="./loadwabac.js"></script> 109 9 <!-- Shell script - manages BackgroundWorker and message routing --> 110 10 <script type="module" src="./seams-shell.js"></script> ··· 127 27 ></iframe> 128 28 <!-- Sidebar container - Sidebar component rendered directly by shell.ts --> 129 29 <div id="sidebar-container" class="sidebar-container"></div> 130 - <button id="toggle-btn" class="sidebar-open" title="Toggle sidebar">&lt;&lt;</button> 30 + <button id="toggle-btn" class="sidebar-open" title="Toggle sidebar">&gt;&gt;</button> 131 31 </div> 132 32 <script> 133 33 // CORS proxy URL - configured at build time via Vite or falls back to localhost for dev ··· 219 119 sidebarContainer.classList.remove('hidden'); 220 120 contentFrame.classList.add('sidebar-open'); 221 121 toggleBtn.classList.add('sidebar-open'); 222 - toggleBtn.innerHTML = '&lt;&lt;'; 122 + toggleBtn.innerHTML = '&gt;&gt;'; // Show >> when open (click to close) 223 123 } else { 224 124 sidebarContainer.classList.add('hidden'); 225 125 contentFrame.classList.remove('sidebar-open'); 226 126 toggleBtn.classList.remove('sidebar-open'); 227 - toggleBtn.innerHTML = '&gt;&gt;'; 127 + toggleBtn.innerHTML = '&lt;&lt;'; // Show << when closed (click to open) 228 128 } 229 129 } 230 130
sure-client-proxy/src/loadwabac.js proxy/src/loadwabac.js
+1 -1
tests/e2e/proxy/create.spec.ts
··· 4 4 * Tests the full flow of creating an annotation through the proxy client. 5 5 * 6 6 * Prerequisites: 7 - * 1. Build the proxy client: pnpm build:via 7 + * 1. Build the proxy client: pnpm build:proxy 8 8 * 2. Start the backend server 9 9 * 3. Start the proxy servers 10 10 * 4. Configure test account in environment:
+1 -1
tests/e2e/proxy/highlights.spec.ts
··· 4 4 * Tests that annotations are correctly highlighted in proxied content. 5 5 * 6 6 * Prerequisites: 7 - * 1. Build the proxy client: pnpm build:via 7 + * 1. Build the proxy client: pnpm build:proxy 8 8 * 2. Start the backend server with test data 9 9 * 3. Start the proxy servers 10 10 */
+3 -3
tests/e2e/proxy/sidebar.spec.ts
··· 4 4 * Tests that the proxy client correctly displays and manages the sidebar. 5 5 * 6 6 * Prerequisites: 7 - * 1. Build the proxy client: pnpm build:via 7 + * 1. Build the proxy client: pnpm build:proxy 8 8 * 2. Start the backend server: pnpm dev:server (or use the webServer config) 9 9 * 3. Start the proxy servers: 10 - * - CORS proxy: cd sure-client-proxy && npx tsx cors-proxy/index.ts 11 - * - Static server: cd sure-client-proxy && npx serve -p 8081 dist 10 + * - CORS proxy: cd proxy && npx tsx cors-proxy/index.ts 11 + * - Static server: cd proxy && npx serve -p 8081 dist 12 12 */ 13 13 14 14 import { test, expect } from '@playwright/test';
+3 -3
vite.sure-client-inject.config.ts vite.proxy-inject.config.ts
··· 1 1 import { defineConfig } from 'vite'; 2 2 import path from 'path'; 3 - import { getEnvDefines } from './vite.sure-client.shared'; 3 + import { getEnvDefines } from './vite.proxy.shared'; 4 4 5 5 // Vite config for the injected seams-client.js script 6 6 // Built as IIFE (self-contained, no ES module imports) for wabac.js injection ··· 8 8 base: '/', 9 9 publicDir: false, // Don't copy public/ to output 10 10 build: { 11 - outDir: 'sure-client-proxy/dist', 11 + outDir: 'proxy/dist', 12 12 emptyOutDir: false, 13 13 sourcemap: true, 14 14 lib: { 15 - entry: path.resolve(__dirname, 'entrypoints/via-client/main.ts'), 15 + entry: path.resolve(__dirname, 'proxy/src/main.ts'), 16 16 name: 'SeamsClient', 17 17 fileName: () => 'seams-client.js', 18 18 formats: ['iife'],
+6 -6
vite.sure-client.config.ts vite.proxy.config.ts
··· 1 1 import { defineConfig } from 'vite'; 2 2 import path from 'path'; 3 - import { getEnvDefines } from './vite.sure-client.shared'; 3 + import { getEnvDefines } from './vite.proxy.shared'; 4 4 5 - // Vite config for sure-client-proxy 5 + // Vite config for proxy 6 6 // Builds the shell (with embedded sidebar) and oauth HTML pages (ES modules) 7 - // The seams-client.js is built separately as IIFE (see vite.sure-client-inject.config.ts) 7 + // The seams-client.js is built separately as IIFE (see vite.proxy-inject.config.ts) 8 8 export default defineConfig({ 9 9 // Base path - files served from root of static server 10 10 base: '/', 11 11 publicDir: false, // Don't copy public/ to output 12 12 build: { 13 - outDir: 'sure-client-proxy/dist', 13 + outDir: 'proxy/dist', 14 14 emptyOutDir: true, 15 15 sourcemap: true, 16 16 rollupOptions: { 17 17 input: { 18 18 // Shell - manages BackgroundWorker, storage, and renders Sidebar directly 19 - 'seams-shell': path.resolve(__dirname, 'sure-client-proxy/html/seams-shell.html'), 19 + 'seams-shell': path.resolve(__dirname, 'proxy/html/seams-shell.html'), 20 20 // OAuth callback page (still needed for popup OAuth flow) 21 - 'oauth-callback': path.resolve(__dirname, 'sure-client-proxy/html/oauth-callback.html'), 21 + 'oauth-callback': path.resolve(__dirname, 'proxy/html/oauth-callback.html'), 22 22 }, 23 23 output: { 24 24 entryFileNames: '[name].js',
+2 -2
vite.sure-client.shared.ts vite.proxy.shared.ts
··· 1 - // Shared configuration for sure-client vite builds 2 - // Used by both vite.sure-client.config.ts and vite.sure-client-inject.config.ts 1 + // Shared configuration for proxy vite builds 2 + // Used by both vite.proxy.config.ts and vite.proxy-inject.config.ts 3 3 4 4 // Development server configuration 5 5 export const DEV_HOST = '127.0.0.1';
-35
vite.via.config.ts
··· 1 - import { defineConfig } from 'vite'; 2 - import path from 'path'; 3 - 4 - // Vite config for production pywb proxy (proxy/static/) 5 - // Note: The sidebar is now embedded directly in the shell, not a separate iframe 6 - export default defineConfig({ 7 - base: '/static/', 8 - build: { 9 - outDir: 'proxy/static', 10 - emptyOutDir: false, 11 - sourcemap: true, 12 - rollupOptions: { 13 - input: { 14 - client: path.resolve(__dirname, 'entrypoints/via-client/main.ts'), 15 - // OAuth callback page (still needed for popup OAuth flow) 16 - 'oauth-callback': path.resolve(__dirname, 'proxy/via-html/oauth-callback.html'), 17 - }, 18 - output: { 19 - entryFileNames: 'seams-[name].js', 20 - format: 'es', 21 - }, 22 - }, 23 - }, 24 - resolve: { 25 - alias: { 26 - '@': path.resolve(__dirname, './'), 27 - }, 28 - }, 29 - define: { 30 - 'import.meta.env.VITE_OAUTH_CLIENT_ID': JSON.stringify(process.env.VITE_OAUTH_CLIENT_ID || 'https://seams.so/oauth/client-metadata.json'), 31 - 'import.meta.env.VITE_OAUTH_REDIRECT_URI': JSON.stringify(process.env.VITE_OAUTH_REDIRECT_URI || 'https://sure.seams.so/oauth-callback.html'), 32 - 'import.meta.env.VITE_OAUTH_SCOPE': JSON.stringify(process.env.VITE_OAUTH_SCOPE || 'atproto transition:generic'), 33 - 'import.meta.env.BACKEND_URL': JSON.stringify(process.env.BACKEND_URL || 'http://localhost:8080'), 34 - }, 35 - });