Social Annotations in the Atmosphere
15
fork

Configure Feed

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

WIP

+4573 -195
+1 -1
.gitignore
··· 46 46 # DNS credentials 47 47 dns/creds.json 48 48 49 - # Via proxy build artifacts 49 + # Via proxy build artifacts (pywb production) 50 50 proxy/static/seams-*.js 51 51 proxy/static/seams-*.js.map 52 52 proxy/static/assets/
+81
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 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 29 + WORKDIR /build 30 + RUN pnpm build:sure-client 31 + 32 + # Runtime stage - Node.js + Caddy 33 + FROM node:22-alpine 34 + 35 + RUN apk add --no-cache bash curl ca-certificates 36 + 37 + # Install Caddy 38 + RUN curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64&arm=" -o /usr/local/bin/caddy \ 39 + && chmod +x /usr/local/bin/caddy 40 + 41 + WORKDIR /app 42 + 43 + # Copy built static files 44 + COPY --from=builder /build/sure-client-proxy/dist/ ./dist/ 45 + 46 + # Copy CORS proxy source and install dependencies 47 + COPY sure-client-proxy/cors-proxy/ ./cors-proxy/ 48 + WORKDIR /app/cors-proxy 49 + RUN npm install 50 + 51 + # Copy Caddyfile 52 + WORKDIR /app 53 + COPY sure-client-proxy/Caddyfile ./ 54 + 55 + # Create startup script 56 + RUN cat <<'EOF' > /app/start.sh 57 + #!/bin/bash 58 + set -e 59 + 60 + echo "Starting Seams Sure Client Proxy..." 61 + 62 + # Start CORS proxy on port 8083 (Caddy proxies 8082 -> 8083) 63 + cd /app/cors-proxy 64 + echo "Starting CORS proxy on :8083..." 65 + CORS_PROXY_PORT=8083 npx tsx index.ts & 66 + CORS_PID=$! 67 + 68 + # Wait for CORS proxy to start 69 + sleep 2 70 + 71 + # Start Caddy (static files on 8081, cors proxy on 8082) 72 + cd /app 73 + echo "Starting Caddy on :8081 (static) and :8082 (cors proxy)..." 74 + caddy run --config /app/Caddyfile --adapter caddyfile 75 + EOF 76 + 77 + RUN chmod +x /app/start.sh 78 + 79 + EXPOSE 8081 8082 80 + 81 + CMD ["/app/start.sh"]
+17
deploy-sure-client.sh
··· 1 + #!/bin/bash 2 + # Deploy Sure Client Proxy to Fly.io 3 + # Usage: ./deploy-sure-client.sh 4 + 5 + set -e 6 + 7 + echo "Deploying Sure Client Proxy to Fly.io..." 8 + 9 + # Build locally first to verify everything works 10 + echo "Building sure-client locally..." 11 + pnpm build:sure-client 12 + 13 + # Deploy to Fly.io 14 + fly deploy --config fly.sure-client.toml 15 + 16 + echo "Deployment complete!" 17 + echo "Visit: https://sure-client-seams-so.fly.dev"
+89 -111
entrypoints/via-client/main.ts
··· 1 - // Via proxy client - injects sidebar iframe and handles page interaction 2 - import { WebStorageAdapter, BackgroundWorker, ProxyContentScript, applyHighlights, clearHighlights, generateSelectors, createMobileAnnotateButton, createMobileSidebarToggle, createMobileAnnotationModal } from '@seams/core'; 3 - import type { Annotation } from '@seams/core'; 1 + // Via proxy client - handles page interaction and communicates with parent frame (shell) 2 + // This runs inside the wabac.js proxied iframe which cannot access localStorage 3 + // Uses PostMessageStorageAdapter to request data from shell 4 + import { PostMessageStorageAdapter, ProxyContentScript, applyHighlights, clearHighlights, generateSelectors } from '@seams/core'; 4 5 5 - console.log('🔬 Seams via client loaded!'); 6 + console.log('[seams-client] Seams via client loaded!'); 6 7 7 - // Initialize web storage adapter 8 - const storage = new WebStorageAdapter(); 8 + // Determine the shell origin from the parent frame 9 + // In production this will be sure.seams.so, in dev it's 127.0.0.1:8081 10 + // Note: Use 127.0.0.1 for local dev (RFC 8252 requires loopback IP for OAuth) 11 + function getShellOrigin(): string { 12 + try { 13 + // Try to get the parent origin - this works if we're same-origin or have access 14 + if (window.parent !== window) { 15 + // We can't directly access parent.location.origin cross-origin, 16 + // but we can use document.referrer as a hint 17 + if (document.referrer) { 18 + const referrerOrigin = new URL(document.referrer).origin; 19 + // Validate it's an allowed origin 20 + if (referrerOrigin === 'https://sure.seams.so' || 21 + referrerOrigin === 'http://127.0.0.1:8081') { 22 + return referrerOrigin; 23 + } 24 + } 25 + } 26 + } catch { 27 + // Ignore errors from cross-origin access 28 + } 29 + // Default to production origin 30 + return 'https://sure.seams.so'; 31 + } 32 + 33 + const shellOrigin = getShellOrigin(); 34 + console.log('[seams-client] Shell origin:', shellOrigin); 9 35 10 - const SIDEBAR_ID = 'seams-sidebar-iframe'; 11 - const SIDEBAR_WIDTH = 400; 12 - const IS_MOBILE = window.innerWidth <= 768; 36 + // Initialize PostMessage storage adapter - requests data from shell (parent frame) 37 + const storage = new PostMessageStorageAdapter(window.parent, shellOrigin); 13 38 14 - // Initialize content script only (sidebar handles fetching via BackgroundWorker) 39 + // Initialize content script - messages go to parent frame which routes to sidebar 15 40 const contentScript = new ProxyContentScript({ 16 41 storage, 17 42 getCurrentUrl: getActualUrl, 18 43 applyHighlights, 19 44 clearHighlights, 20 45 generateSelectors, 21 - onAnnotate: (data) => { 22 - const iframe = document.getElementById(SIDEBAR_ID) as HTMLIFrameElement; 23 - if (!iframe || !iframe.contentWindow) return; 24 - 25 - // Always use desktop flow: Activate form 26 - iframe.contentWindow.postMessage({ 27 - type: 'ACTIVATE_ANNOTATION', 28 - payload: null 29 - }, '*'); 30 - 31 - // Mobile handling: If sidebar is hidden, show it 32 - if (IS_MOBILE) { 33 - const isHidden = iframe.style.display === 'none'; 34 - if (isHidden) { 35 - iframe.style.display = 'block'; 36 - // We should also update the toggle button text if we could access it, 37 - // but it's inside a closure in injectSidebar. 38 - // Ideally we should trigger the toggle logic. 39 - } 40 - } 46 + onAnnotate: () => { 47 + // Send activation message to parent frame 48 + window.parent.postMessage({ 49 + type: 'ACTIVATE_ANNOTATION', 50 + payload: null 51 + }, shellOrigin); 41 52 }, 42 53 onSelectionChange: (selection) => { 43 - const iframe = document.getElementById(SIDEBAR_ID) as HTMLIFrameElement; 44 - if (iframe && iframe.contentWindow) { 45 - iframe.contentWindow.postMessage({ 46 - type: 'SELECTION_CHANGED', 47 - payload: selection 48 - }, '*'); 49 - } 54 + // Send selection to parent frame which routes to sidebar 55 + window.parent.postMessage({ 56 + type: 'SELECTION_CHANGED', 57 + payload: selection 58 + }, shellOrigin); 50 59 } 51 60 }); 52 61 53 - function injectSidebar() { 54 - // Don't inject if already present 55 - if (document.getElementById(SIDEBAR_ID)) { 56 - console.log('[seams-via] Sidebar already injected'); 57 - return; 58 - } 59 - 60 - // Create iframe for sidebar 61 - const iframe = document.createElement('iframe'); 62 - iframe.id = SIDEBAR_ID; 63 - // Use relative URL to load through Caddy proxy (same origin for CSP) 64 - iframe.src = '/static/seams-sidebar.html'; 65 - iframe.style.cssText = ` 66 - position: fixed; 67 - top: 0; 68 - right: 0; 69 - width: ${SIDEBAR_WIDTH}px; 70 - height: 100dvh; 71 - border: none; 72 - border-left: 1px solid #ccc; 73 - z-index: 2147483647; 74 - background: white; 75 - box-shadow: -2px 0 8px rgba(0,0,0,0.1); 76 - `; 77 - 78 - document.body.appendChild(iframe); 79 - console.log('[seams-via] Sidebar injected'); 80 - 81 - // Adjust page content to avoid overlap (only on desktop) 82 - if (!IS_MOBILE) { 83 - document.body.style.marginRight = `${SIDEBAR_WIDTH}px`; 84 - } else { 85 - iframe.style.width = '100%'; 86 - iframe.style.display = 'none'; // Hidden by default on mobile 87 - } 88 - 89 - // When iframe loads, send the URL 90 - iframe.onload = () => { 91 - console.log('[seams-via] Sidebar iframe loaded, sending URL'); 92 - iframe.contentWindow?.postMessage({ 93 - type: 'SEAMS_PAGE_URL', 94 - url: getActualUrl(), 95 - }, '*'); 96 - }; 97 - 98 - // Add toggle button for mobile 99 - if (IS_MOBILE) { 100 - const toggleBtn = createMobileSidebarToggle(() => { 101 - const isHidden = iframe.style.display === 'none'; 102 - iframe.style.display = isHidden ? 'block' : 'none'; 103 - toggleBtn.textContent = isHidden ? '>>' : '<<'; 104 - }); 105 - } 106 - } 107 - 108 62 function normalizeUrl(url: string): string { 109 63 try { 110 64 const parsed = new URL(url); ··· 123 77 } 124 78 125 79 function getActualUrl(): string { 126 - // Extract actual URL from pywb proxy URL 127 - // URL format: http://localhost:8081/proxy/https://example.com 128 80 const proxyUrl = window.location.href; 129 81 130 - // Try to get from wbinfo (pywb metadata) 82 + // Try to get from wbinfo (wabac.js/pywb metadata object) 83 + // wabac.js injects this with the original URL 131 84 const wbinfo = (window as any).wbinfo; 132 85 if (wbinfo && wbinfo.url) { 133 86 const rawUrl = wbinfo.url; ··· 137 90 return normalized; 138 91 } 139 92 140 - // Fallback: parse from proxy URL 141 - const match = proxyUrl.match(/\/proxy\/(https?:\/\/.+)/); 142 - if (match) { 143 - const rawUrl = match[1]; 93 + // Fallback: parse from wabac.js proxy URL pattern 94 + // URL format: /w/liveproxy/mp_/https://example.com 95 + // or with timestamp: /w/liveproxy/20231225mp_/https://example.com 96 + const wabacMatch = proxyUrl.match(/\/w\/[^/]+\/(?:\d+)?[a-z]{2}_\/(https?:\/\/.+)/); 97 + if (wabacMatch) { 98 + const rawUrl = wabacMatch[1]; 144 99 const normalized = normalizeUrl(rawUrl); 145 - console.log('[seams-via] Extracted URL from proxy path:', rawUrl); 100 + console.log('[seams-via] Extracted URL from wabac.js path:', rawUrl); 101 + console.log('[seams-via] Normalized URL:', normalized); 102 + return normalized; 103 + } 104 + 105 + // Fallback: parse from pywb proxy URL 106 + // URL format: http://localhost:8081/proxy/https://example.com 107 + const pywbMatch = proxyUrl.match(/\/proxy\/(https?:\/\/.+)/); 108 + if (pywbMatch) { 109 + const rawUrl = pywbMatch[1]; 110 + const normalized = normalizeUrl(rawUrl); 111 + console.log('[seams-via] Extracted URL from pywb path:', rawUrl); 146 112 console.log('[seams-via] Normalized URL:', normalized); 147 113 return normalized; 148 114 } ··· 153 119 154 120 // Initialize 155 121 function init() { 156 - if (document.body) { 157 - injectSidebar(); 158 - } else { 159 - document.addEventListener('DOMContentLoaded', () => { 160 - injectSidebar(); 161 - }); 162 - } 122 + // Send initial URL to parent frame 123 + const url = getActualUrl(); 124 + console.log('[seams-client] Sending initial URL to parent:', url); 125 + window.parent.postMessage({ 126 + type: 'SEAMS_PAGE_URL', 127 + url: url 128 + }, shellOrigin); 163 129 164 - // Start content script (loads and renders annotations from localStorage) 130 + // Start content script (loads and renders annotations via PostMessage from shell) 165 131 contentScript.start(); 166 132 } 167 133 168 - init(); 134 + // Wait for DOM to be ready 135 + if (document.readyState === 'loading') { 136 + document.addEventListener('DOMContentLoaded', init); 137 + } else { 138 + init(); 139 + } 169 140 170 - // Listen for messages from sidebar 171 - // window.addEventListener('message', (event) => { ... }); 141 + // Also send URL on popstate (back/forward navigation within proxied page) 142 + window.addEventListener('popstate', () => { 143 + const url = getActualUrl(); 144 + console.log('[seams-client] Navigation detected, sending URL to parent:', url); 145 + window.parent.postMessage({ 146 + type: 'SEAMS_PAGE_URL', 147 + url: url 148 + }, shellOrigin); 149 + });
+269
entrypoints/via-client/shell.ts
··· 1 + // Shell entry point - runs in the parent frame 2 + // Manages BackgroundWorker, storage, and renders Sidebar directly (no iframe) 3 + import { 4 + WebStorageAdapter, 5 + BackgroundWorker, 6 + fetchAnnotations, 7 + Sidebar, 8 + PopupOAuthLauncher, 9 + } from '@seams/core'; 10 + 11 + // Import sidebar CSS - will be scoped to .sidebar-container 12 + import sidebarStyles from '../sidepanel/style.css?inline'; 13 + 14 + console.log('[shell] Seams shell loading...'); 15 + 16 + // Configuration 17 + const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || import.meta.env.BACKEND_URL || 'https://seams.so'; 18 + 19 + // Initialize storage (localStorage accessible from shell) 20 + const storage = new WebStorageAdapter(); 21 + 22 + // Initialize background worker 23 + const backgroundWorker = new BackgroundWorker({ 24 + storage, 25 + fetchAnnotations: async (url: string) => { 26 + return fetchAnnotations(BACKEND_URL, url); 27 + }, 28 + }); 29 + 30 + // Track current page URL 31 + let currentUrl: string | null = null; 32 + 33 + // Get iframe reference for content (set after DOM ready) 34 + let contentFrame: HTMLIFrameElement | null = null; 35 + 36 + // Sidebar instance (created after DOM ready) 37 + let sidebar: Sidebar | null = null; 38 + 39 + // Listen for storage changes and push to content iframe 40 + storage.onChange((change) => { 41 + if (change.key === 'annotations') { 42 + console.log('[shell] Annotations updated in storage, pushing to content iframe'); 43 + pushAnnotationsToContent(); 44 + } 45 + }); 46 + 47 + // Safely post a message to the content iframe 48 + // Returns false if the iframe is not accessible (e.g., cross-origin before SW intercepts) 49 + function postToContent(message: object): boolean { 50 + if (!contentFrame) { 51 + console.warn('[shell] Content frame not available'); 52 + return false; 53 + } 54 + 55 + try { 56 + // Accessing contentWindow can throw if cross-origin 57 + const contentWindow = contentFrame.contentWindow; 58 + if (!contentWindow) { 59 + console.warn('[shell] Content frame window not available'); 60 + return false; 61 + } 62 + // Content iframe is same-origin (served via service worker) 63 + contentWindow.postMessage(message, window.location.origin); 64 + return true; 65 + } catch (error) { 66 + // This can happen if the iframe content hasn't been intercepted by the service worker yet 67 + console.warn('[shell] Cannot access content iframe (may be cross-origin):', error); 68 + return false; 69 + } 70 + } 71 + 72 + // Push current annotations to content iframe 73 + async function pushAnnotationsToContent(): Promise<void> { 74 + try { 75 + const annotations = await storage.get('annotations') || []; 76 + console.log('[shell] Pushing', annotations.length, 'annotations to content iframe'); 77 + postToContent({ 78 + type: 'ANNOTATIONS_UPDATED', 79 + annotations 80 + }); 81 + } catch (error) { 82 + console.error('[shell] Failed to push annotations to content:', error); 83 + } 84 + } 85 + 86 + // Handle GET_ANNOTATIONS request from content iframe 87 + async function handleGetAnnotations(requestId: string): Promise<void> { 88 + try { 89 + const annotations = await storage.get('annotations') || []; 90 + console.log('[shell] Responding to GET_ANNOTATIONS with', annotations.length, 'annotations'); 91 + postToContent({ 92 + type: 'ANNOTATIONS_DATA', 93 + requestId, 94 + annotations 95 + }); 96 + } catch (error) { 97 + console.error('[shell] Failed to get annotations for request:', error); 98 + postToContent({ 99 + type: 'ANNOTATIONS_DATA', 100 + requestId, 101 + annotations: [] 102 + }); 103 + } 104 + } 105 + 106 + // Handle messages from content iframe 107 + function handleMessage(event: MessageEvent): void { 108 + // Validate origin - content iframe is same-origin via service worker 109 + if (event.origin !== window.location.origin) { 110 + return; 111 + } 112 + 113 + const { type, requestId, url, payload } = event.data; 114 + 115 + // Only handle messages from content iframe 116 + const isFromContent = contentFrame && event.source === contentFrame.contentWindow; 117 + 118 + if (!isFromContent) return; 119 + 120 + console.log('[shell] Message from content iframe:', type); 121 + 122 + switch (type) { 123 + case 'GET_ANNOTATIONS': 124 + handleGetAnnotations(requestId); 125 + break; 126 + 127 + case 'SEAMS_PAGE_URL': 128 + // Update current URL and trigger background worker fetch 129 + if (url && url !== currentUrl) { 130 + currentUrl = url; 131 + console.log('[shell] Page URL changed:', url); 132 + backgroundWorker.setCurrentUrl(url); 133 + } 134 + // Update sidebar directly 135 + if (sidebar) { 136 + sidebar.setCurrentUrl(url); 137 + } 138 + break; 139 + 140 + case 'SELECTION_CHANGED': 141 + // Update sidebar directly 142 + if (sidebar) { 143 + sidebar.setSelection(payload); 144 + } 145 + break; 146 + 147 + case 'ACTIVATE_ANNOTATION': 148 + // Activate sidebar directly 149 + if (sidebar) { 150 + sidebar.handleActivateAnnotation(); 151 + } 152 + break; 153 + 154 + default: 155 + console.log('[shell] Unknown message type from content:', type); 156 + } 157 + } 158 + 159 + // Inject scoped sidebar CSS 160 + function injectScopedStyles(): void { 161 + // Scope all CSS rules under .sidebar-container 162 + // This prevents the sidebar CSS from affecting the shell page 163 + const scopedStyles = sidebarStyles 164 + // Scope body rules to .sidebar-container 165 + .replace(/\bbody\s*\{/g, '.sidebar-container {') 166 + .replace(/\bbody::before\s*\{/g, '.sidebar-container::before {') 167 + // Scope universal selector - be more selective 168 + .replace(/^\*\s*\{/gm, '.sidebar-container * {') 169 + // Keep :root as-is (CSS variables) 170 + ; 171 + 172 + const styleEl = document.createElement('style'); 173 + styleEl.textContent = scopedStyles; 174 + document.head.appendChild(styleEl); 175 + console.log('[shell] Injected scoped sidebar styles'); 176 + } 177 + 178 + // Initialize sidebar 179 + function initSidebar(): void { 180 + const sidebarContainer = document.getElementById('sidebar-container'); 181 + if (!sidebarContainer) { 182 + console.error('[shell] Sidebar container not found'); 183 + return; 184 + } 185 + 186 + // Create the app div inside the container (Sidebar expects an element to render into) 187 + const appDiv = document.createElement('div'); 188 + appDiv.id = 'sidebar-app'; 189 + sidebarContainer.appendChild(appDiv); 190 + 191 + // Use PopupOAuthLauncher - popup flow works better than redirect for shell context 192 + const launcher = new PopupOAuthLauncher(); 193 + 194 + sidebar = new Sidebar( 195 + appDiv, 196 + storage, 197 + launcher, 198 + { 199 + oauth: { 200 + // Note: These env vars are replaced at build time by vite.sure-client.config.ts 201 + // For development, VITE_OAUTH_CLIENT_ID uses the loopback format: http://localhost?redirect_uri=...&scope=... 202 + clientId: import.meta.env.VITE_OAUTH_CLIENT_ID, 203 + redirectUri: import.meta.env.VITE_OAUTH_REDIRECT_URI, 204 + scope: import.meta.env.VITE_OAUTH_SCOPE || 'atproto transition:generic', 205 + }, 206 + pds: { 207 + backendUrl: BACKEND_URL, 208 + }, 209 + }, 210 + () => { 211 + // Sync callback - directly call backgroundWorker 212 + console.log('[shell] Sidebar requested sync'); 213 + backgroundWorker.forceSync(); 214 + } 215 + ); 216 + 217 + // If we already have a URL, set it on the sidebar 218 + if (currentUrl) { 219 + sidebar.setCurrentUrl(currentUrl); 220 + } 221 + 222 + console.log('[shell] Sidebar initialized'); 223 + } 224 + 225 + // Initialize when DOM is ready 226 + function init(): void { 227 + console.log('[shell] Initializing...'); 228 + 229 + // Get content iframe reference 230 + contentFrame = document.getElementById('content') as HTMLIFrameElement; 231 + 232 + if (!contentFrame) { 233 + console.error('[shell] Content iframe not found'); 234 + } 235 + 236 + // Inject scoped CSS and initialize sidebar 237 + injectScopedStyles(); 238 + initSidebar(); 239 + 240 + // Listen for messages from content iframe 241 + window.addEventListener('message', handleMessage); 242 + 243 + console.log('[shell] Ready'); 244 + } 245 + 246 + // Wait for DOM 247 + if (document.readyState === 'loading') { 248 + document.addEventListener('DOMContentLoaded', init); 249 + } else { 250 + init(); 251 + } 252 + 253 + // Export for external access (e.g., from inline script in index.html) 254 + (window as any).SeamsShell = { 255 + setUrl: (url: string) => { 256 + if (url && url !== currentUrl) { 257 + currentUrl = url; 258 + console.log('[shell] URL set externally:', url); 259 + backgroundWorker.setCurrentUrl(url); 260 + if (sidebar) { 261 + sidebar.setCurrentUrl(url); 262 + } 263 + } 264 + }, 265 + forceSync: () => { 266 + backgroundWorker.forceSync(); 267 + }, 268 + getCurrentUrl: () => currentUrl, 269 + };
-59
entrypoints/via-client/sidebar.ts
··· 1 - import '../sidepanel/style.css'; 2 - import { WebStorageAdapter, WebOAuthLauncher, Sidebar, BackgroundWorker, fetchAnnotations } from '@seams/core'; 3 - 4 - console.log('[seams-sidebar] Loading sidebar (v2.1)...'); 5 - 6 - const app = document.getElementById('app'); 7 - if (!app) { 8 - throw new Error('App element not found'); 9 - } 10 - 11 - const storage = new WebStorageAdapter(); 12 - const launcher = new WebOAuthLauncher(); 13 - 14 - const backgroundWorker = new BackgroundWorker({ 15 - storage, 16 - fetchAnnotations: async (url: string) => { 17 - const backendUrl = import.meta.env.VITE_BACKEND_URL || import.meta.env.BACKEND_URL || 'https://seams.so'; 18 - return fetchAnnotations(backendUrl, url); 19 - }, 20 - }); 21 - 22 - const sidebar = new Sidebar( 23 - app, 24 - storage, 25 - launcher, 26 - { 27 - oauth: { 28 - clientId: import.meta.env.VITE_OAUTH_CLIENT_ID || 'http://localhost:8081/static/client-metadata.json', 29 - redirectUri: import.meta.env.VITE_OAUTH_REDIRECT_URI || 'http://localhost:8081/static/oauth-callback.html', 30 - scope: import.meta.env.VITE_OAUTH_SCOPE || 'atproto transition:generic', 31 - }, 32 - pds: { 33 - backendUrl: import.meta.env.VITE_BACKEND_URL || import.meta.env.BACKEND_URL || 'https://seams.so', 34 - }, 35 - }, 36 - () => { 37 - backgroundWorker.forceSync(); 38 - } 39 - ); 40 - 41 - // Listen for messages from parent (page URL) 42 - window.addEventListener('message', (event) => { 43 - if (event.data.type === 'SEAMS_PAGE_URL') { 44 - const url = event.data.url; 45 - console.log('[seams-sidebar] Received page URL:', url); 46 - sidebar.setCurrentUrl(url); 47 - backgroundWorker.setCurrentUrl(url); 48 - } else if (event.data.type === 'SELECTION_CHANGED') { 49 - console.log('[seams-sidebar] Received selection update'); 50 - sidebar.setSelection(event.data.payload); 51 - } else if (event.data.type === 'ACTIVATE_ANNOTATION') { 52 - console.log('[seams-sidebar] Received activation request'); 53 - sidebar.handleActivateAnnotation(); 54 - } 55 - }); 56 - 57 - // Notify parent window that sidebar is ready 58 - window.parent.postMessage({ type: 'SEAMS_SIDEBAR_READY' }, '*'); 59 - console.log('[seams-sidebar] Ready');
+87 -1
flake.nix
··· 12 12 let 13 13 pkgs = nixpkgs.legacyPackages.${system}; 14 14 15 + # Path to sure-client-proxy dist (must be built before nix build) 16 + # 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 + 15 23 # Build Go backend server 16 24 server = pkgs.buildGoModule { 17 25 pname = "seams-server"; ··· 72 80 }; 73 81 }; 74 82 75 - # Docker image for Via Proxy 83 + # Docker image for Sure Client Proxy (wabac.js-based) 84 + # Uses Caddy for static files + Node.js CORS proxy 85 + sureClientProxy = pkgs.dockerTools.buildImage { 86 + name = "seams-sure-client-proxy"; 87 + tag = "latest"; 88 + 89 + copyToRoot = pkgs.buildEnv { 90 + name = "image-root"; 91 + paths = [ 92 + pkgs.coreutils 93 + pkgs.bash 94 + pkgs.caddy 95 + pkgs.nodejs_22 96 + pkgs.cacert 97 + 98 + # 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" {} '' 102 + mkdir -p $out/app/dist 103 + mkdir -p $out/app/cors-proxy 104 + 105 + # Copy built static files 106 + cp -r ${sureClientDist}/* $out/app/dist/ 107 + 108 + # Copy CORS proxy source 109 + cp -r ${./sure-client-proxy/cors-proxy}/* $out/app/cors-proxy/ 110 + 111 + # Copy Caddyfile 112 + cp ${./sure-client-proxy/Caddyfile} $out/app/Caddyfile 113 + '') 114 + 115 + # Startup script 116 + (pkgs.writeScriptBin "start-sure-client.sh" '' 117 + #!${pkgs.bash}/bin/bash 118 + set -e 119 + 120 + echo "Starting Seams Sure Client Proxy..." 121 + 122 + # Ensure HOME exists for npm 123 + ${pkgs.coreutils}/bin/mkdir -p /root 124 + 125 + # Install CORS proxy dependencies 126 + cd /app/cors-proxy 127 + echo "Installing CORS proxy dependencies..." 128 + ${pkgs.nodejs_22}/bin/npm install --production 2>/dev/null || ${pkgs.nodejs_22}/bin/npm install 129 + 130 + # Start CORS proxy on port 8083 (internal, Caddy proxies to 8082) 131 + echo "Starting CORS proxy on :8083..." 132 + CORS_PROXY_PORT=8083 CORS_ALLOWED_ORIGINS="$CORS_ALLOWED_ORIGINS" ${pkgs.nodejs_22}/bin/npx tsx index.ts & 133 + CORS_PID=$! 134 + 135 + # Wait for CORS proxy to start 136 + ${pkgs.coreutils}/bin/sleep 2 137 + 138 + # Start Caddy (static files on 8081, proxy to cors on 8082) 139 + cd /app 140 + echo "Starting Caddy on :8081 (static) and :8082 (cors proxy)..." 141 + ${pkgs.caddy}/bin/caddy run --config /app/Caddyfile --adapter caddyfile 142 + '') 143 + ]; 144 + pathsToLink = [ "/bin" "/app" ]; 145 + }; 146 + 147 + config = { 148 + Cmd = [ "start-sure-client.sh" ]; 149 + ExposedPorts = { "8081/tcp" = {}; "8082/tcp" = {}; }; 150 + WorkingDir = "/app"; 151 + Env = [ 152 + "PATH=/bin" 153 + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" 154 + "HOME=/root" 155 + # Default CORS origins - override with CORS_ALLOWED_ORIGINS env var 156 + "CORS_ALLOWED_ORIGINS=http://localhost:8081,http://127.0.0.1:8081" 157 + ]; 158 + }; 159 + }; 160 + 161 + # Docker image for Via Proxy (pywb-based, legacy) 76 162 proxy = pkgs.dockerTools.buildImage { 77 163 name = "seams-proxy"; 78 164 tag = "latest";
+33
fly.sure-client.toml
··· 1 + # fly.sure-client.toml app configuration for Sure Client Proxy (wabac.js-based) 2 + # Deploy with: fly deploy --config fly.sure-client.toml 3 + app = 'sure-client-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 + # Override with production domain 33 + CORS_ALLOWED_ORIGINS = "https://sure-client-seams-so.fly.dev"
+2
package.json
··· 10 10 "build:landing": "vite build --config vite.landing.config.ts", 11 11 "build:via": "vite build --config vite.via.config.ts && bash scripts/postbuild-via.sh", 12 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", 13 15 "dev:server": "pnpm run build:landing && cd server && air", 14 16 "via": "bash scripts/start-via.sh" 15 17 },
+1
packages/core/src/storage/index.ts
··· 1 1 export type { StorageAdapter, StorageChange } from './adapter'; 2 2 export { WebStorageAdapter } from './web'; 3 3 export { BrowserStorageAdapter } from './browser'; 4 + export { PostMessageStorageAdapter } from './postmessage';
+143
packages/core/src/storage/postmessage.ts
··· 1 + // PostMessage storage adapter for cross-origin iframes 2 + // Used by content script in wabac.js proxied iframe which cannot access localStorage 3 + // Communicates with shell (parent window) which has localStorage access 4 + 5 + import type { StorageAdapter, StorageChange } from './adapter'; 6 + 7 + // Allowed origins for postMessage communication 8 + // Note: Use 127.0.0.1 for local dev (RFC 8252 requires loopback IP for OAuth) 9 + const ALLOWED_ORIGINS = [ 10 + 'http://127.0.0.1:8081', 11 + 'https://sure.seams.so', 12 + ]; 13 + 14 + interface PendingRequest { 15 + resolve: (value: any) => void; 16 + reject: (error: Error) => void; 17 + } 18 + 19 + export class PostMessageStorageAdapter implements StorageAdapter { 20 + private listeners: Array<(change: StorageChange) => void> = []; 21 + private pendingRequests: Map<string, PendingRequest> = new Map(); 22 + private targetWindow: Window; 23 + private targetOrigin: string; 24 + private boundHandleMessage: (event: MessageEvent) => void; 25 + 26 + constructor(targetWindow: Window = window.parent, targetOrigin: string = 'https://sure.seams.so') { 27 + this.targetWindow = targetWindow; 28 + this.targetOrigin = targetOrigin; 29 + 30 + // Bind handler once so we can remove it later 31 + this.boundHandleMessage = this.handleMessage.bind(this); 32 + 33 + // Listen for messages from shell 34 + window.addEventListener('message', this.boundHandleMessage); 35 + } 36 + 37 + private handleMessage(event: MessageEvent): void { 38 + // Validate origin - only accept messages from allowed origins 39 + if (!ALLOWED_ORIGINS.includes(event.origin)) { 40 + return; 41 + } 42 + 43 + const { type, requestId, annotations, key, newValue, oldValue } = event.data; 44 + 45 + if (type === 'ANNOTATIONS_DATA' && requestId) { 46 + // Response to GET_ANNOTATIONS request 47 + const pending = this.pendingRequests.get(requestId); 48 + if (pending) { 49 + this.pendingRequests.delete(requestId); 50 + pending.resolve(annotations); 51 + } 52 + } else if (type === 'ANNOTATIONS_UPDATED') { 53 + // Push notification from shell when storage changes 54 + console.log('[PostMessageStorageAdapter] Received annotations update'); 55 + const change: StorageChange = { 56 + key: 'annotations', 57 + newValue: annotations, 58 + oldValue: undefined 59 + }; 60 + this.listeners.forEach(callback => callback(change)); 61 + } else if (type === 'STORAGE_CHANGE') { 62 + // Generic storage change notification 63 + const change: StorageChange = { key, newValue, oldValue }; 64 + this.listeners.forEach(callback => callback(change)); 65 + } 66 + } 67 + 68 + async get(keys: string | string[]): Promise<any> { 69 + // For now, we only support getting 'annotations' 70 + // This could be extended to support other keys if needed 71 + if (keys === 'annotations' || (Array.isArray(keys) && keys.includes('annotations'))) { 72 + return this.requestAnnotations(); 73 + } 74 + 75 + // For single key 76 + if (typeof keys === 'string') { 77 + if (keys === 'annotations') { 78 + return this.requestAnnotations(); 79 + } 80 + // Unsupported key - return null 81 + console.warn('[PostMessageStorageAdapter] Unsupported key:', keys); 82 + return null; 83 + } 84 + 85 + // For multiple keys 86 + const result: Record<string, any> = {}; 87 + for (const key of keys) { 88 + if (key === 'annotations') { 89 + result[key] = await this.requestAnnotations(); 90 + } else { 91 + result[key] = null; 92 + } 93 + } 94 + return result; 95 + } 96 + 97 + private requestAnnotations(): Promise<any> { 98 + return new Promise((resolve, reject) => { 99 + const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; 100 + 101 + // Set up timeout 102 + const timeout = setTimeout(() => { 103 + this.pendingRequests.delete(requestId); 104 + console.warn('[PostMessageStorageAdapter] GET_ANNOTATIONS request timed out'); 105 + resolve([]); // Return empty array on timeout rather than rejecting 106 + }, 5000); 107 + 108 + this.pendingRequests.set(requestId, { 109 + resolve: (value) => { 110 + clearTimeout(timeout); 111 + resolve(value); 112 + }, 113 + reject: (error) => { 114 + clearTimeout(timeout); 115 + reject(error); 116 + } 117 + }); 118 + 119 + // Send request to shell 120 + console.log('[PostMessageStorageAdapter] Requesting annotations from shell'); 121 + this.targetWindow.postMessage({ 122 + type: 'GET_ANNOTATIONS', 123 + requestId 124 + }, this.targetOrigin); 125 + }); 126 + } 127 + 128 + async set(_key: string, _value: any): Promise<void> { 129 + // Content script doesn't write to storage - it's read-only 130 + // Writes happen through sidebar -> PDS -> storage in shell 131 + console.warn('[PostMessageStorageAdapter] set() called but content script is read-only'); 132 + } 133 + 134 + onChange(callback: (change: StorageChange) => void): void { 135 + this.listeners.push(callback); 136 + } 137 + 138 + destroy(): void { 139 + window.removeEventListener('message', this.boundHandleMessage); 140 + this.pendingRequests.clear(); 141 + this.listeners = []; 142 + } 143 + }
+21 -5
proxy/static/extension-callback.html
··· 5 5 <title>OAuth Callback</title> 6 6 </head> 7 7 <body> 8 - <p>Authenticated. This window will close automatically.</p> 8 + <p>Redirecting...</p> 9 9 <script> 10 - // Log what we received to help debug 11 - console.log('[extension-callback] Full URL:', window.location.href); 12 - console.log('[extension-callback] Search:', window.location.search); 13 - console.log('[extension-callback] Hash:', window.location.hash); 10 + // Relay to Chromium extension callback 11 + const extensionId = 'kjdnjfgcikmlbloojphbkmknfpmfofio'; 12 + const extRedirect = `https://${extensionId}.chromiumapp.org/extension-callback.html`; 13 + 14 + // Check if we are already in the extension context to avoid infinite loops 15 + const isExtension = window.location.protocol === 'chrome-extension:' || 16 + window.location.hostname.endsWith('.chromiumapp.org') || 17 + window.location.protocol === 'moz-extension:'; 18 + 19 + if (!isExtension) { 20 + // We are on the web server (relay), so redirect to the extension 21 + console.log('Relaying to extension:', extRedirect); 22 + window.location.href = extRedirect + window.location.search + window.location.hash; 23 + } else { 24 + // We are in the extension 25 + console.log('Authentication successful!'); 26 + // The browser should handle closing this window via launchWebAuthFlow, 27 + // but we can show a message just in case. 28 + document.querySelector('p').textContent = 'Authenticated. This window will close automatically.'; 29 + } 14 30 </script> 15 31 </body> 16 32 </html>
proxy/static/favicon.ico

This is a binary file and will not be displayed.

proxy/static/icon-128.png

This is a binary file and will not be displayed.

proxy/static/icon-16.png

This is a binary file and will not be displayed.

proxy/static/icon-32.png

This is a binary file and will not be displayed.

proxy/static/icon-48.png

This is a binary file and will not be displayed.

+28 -3
proxy/static/landing.css
··· 81 81 text-transform: uppercase; 82 82 color: #666; 83 83 margin-bottom: 24px; 84 + position: relative; 85 + display: inline-block; 86 + } 87 + 88 + .logo sup { 89 + font-size: 0.6em; 90 + text-transform: lowercase; 91 + color: var(--forest-green); 92 + font-weight: 500; 93 + letter-spacing: 0; 94 + vertical-align: super; 95 + margin-left: 2px; 84 96 } 85 97 86 98 .hero h1 { ··· 421 433 display: flex; 422 434 gap: 10px; 423 435 width: 100%; 436 + align-items: stretch; 424 437 } 425 438 426 439 .url-form input[type="url"] { ··· 432 445 transition: border-color 0.2s; 433 446 font-family: inherit; 434 447 background: #fff; 448 + min-width: 0; 435 449 } 436 450 437 451 .url-form input[type="url"]:focus { ··· 451 465 transition: all 0.2s; 452 466 white-space: nowrap; 453 467 font-family: inherit; 468 + flex-shrink: 0; 469 + min-width: fit-content; 454 470 } 455 471 456 472 .url-form button[type="submit"]:hover { ··· 479 495 transform: translateY(-50%); 480 496 height: 70%; 481 497 width: auto; 482 - opacity: 0.05; 498 + opacity: 0.15; 483 499 z-index: 0; 484 500 pointer-events: none; 485 501 /* Filter to make it monochrome if needed, or use opacity */ ··· 492 508 493 509 @media (max-width: 1024px) { 494 510 .sidebar-bg-logo { 495 - right: -10%; 496 - height: 60%; 511 + right: 50%; 512 + transform: translate(50%, -50%); 513 + height: 100%; 514 + top: 50%; 515 + opacity: 0.15; 516 + } 517 + } 518 + 519 + @media (max-width: 640px) { 520 + .sidebar-bg-logo { 521 + height: 50vh; 497 522 } 498 523 }
+1 -2
proxy/static/oauth-callback.html
··· 58 58 } 59 59 </style> 60 60 <script type="module" crossorigin src="/static/seams-oauth-callback.js"></script> 61 - <link rel="modulepreload" crossorigin href="/static/assets/modulepreload-polyfill-Elc7_Ely.js"> 62 - <link rel="modulepreload" crossorigin href="/static/assets/index-BKdQD0EM.js"> 61 + <link rel="modulepreload" crossorigin href="/static/assets/index-DkUoX9_k.js"> 63 62 </head> 64 63 <body> 65 64 <div class="callback-container">
-12
proxy/via-html/seams-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="../../entrypoints/via-client/sidebar.ts"></script> 11 - </body> 12 - </html>
+35
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 + OUT_DIR="sure-client-proxy/dist" 7 + SRC_DIR="sure-client-proxy/src" 8 + NESTED_DIR="$OUT_DIR/sure-client-proxy/html" 9 + 10 + # Move HTML files from nested vite output to root 11 + if [ -d "$NESTED_DIR" ]; then 12 + mv "$NESTED_DIR"/*.html "$OUT_DIR/" 13 + rm -rf "$OUT_DIR/sure-client-proxy" 14 + echo "Flattened HTML files" 15 + fi 16 + 17 + # Copy source files 18 + cp "$SRC_DIR/index.html" "$OUT_DIR/" 19 + cp "$SRC_DIR/loadwabac.js" "$OUT_DIR/" 20 + cp "$SRC_DIR/client-metadata.json" "$OUT_DIR/" 21 + echo "Copied source files from $SRC_DIR" 22 + 23 + # Copy wabac.js service worker 24 + WABAC_SW="sure-client-proxy/node_modules/@webrecorder/wabac/dist/sw.js" 25 + if [ -f "$WABAC_SW" ]; then 26 + cp "$WABAC_SW" "$OUT_DIR/" 27 + echo "Copied wabac.js service worker" 28 + else 29 + echo "WARNING: wabac.js sw.js not found at $WABAC_SW" 30 + echo "Run 'cd sure-client-proxy && npm install' to install dependencies" 31 + fi 32 + 33 + echo "" 34 + echo "Build complete. Files in $OUT_DIR/:" 35 + ls -la "$OUT_DIR"/*.html "$OUT_DIR"/*.js "$OUT_DIR"/*.json 2>/dev/null
+2
sure-client-proxy/.gitignore
··· 1 + dist/ 2 + node_modules/
+35
sure-client-proxy/Caddyfile
··· 1 + # Caddyfile for sure-client-proxy 2 + # Serves static files on :8081, reverse proxies CORS proxy on :8082 3 + 4 + # Static file server for wabac.js client 5 + :8081 { 6 + root * /app/dist 7 + file_server 8 + 9 + # Enable gzip compression 10 + encode gzip 11 + 12 + # CORS headers for service worker and client 13 + header { 14 + Access-Control-Allow-Origin * 15 + Access-Control-Allow-Methods "GET, POST, OPTIONS" 16 + Access-Control-Allow-Headers "*" 17 + } 18 + 19 + # Cache static assets 20 + @static { 21 + path *.js *.css *.woff *.woff2 *.png *.ico 22 + } 23 + header @static Cache-Control "public, max-age=3600" 24 + 25 + # Don't cache HTML (for updates) 26 + @html { 27 + path *.html / 28 + } 29 + header @html Cache-Control "no-cache" 30 + } 31 + 32 + # CORS proxy (reverse proxy to Node.js server) 33 + :8082 { 34 + reverse_proxy localhost:8083 35 + }
+89
sure-client-proxy/README.md
··· 1 + # Seams Client-Side Proxy POC 2 + 3 + A client-side web proxy using wabac.js, replacing the server-side pywb proxy. 4 + 5 + ## Architecture 6 + 7 + Instead of fetching pages server-side (pywb), this approach uses: 8 + 9 + 1. **CORS Proxy** (`cors-proxy/`) - Lightweight Node.js server that adds CORS headers 10 + 2. **wabac.js Service Worker** - Intercepts requests in the browser and routes through CORS proxy 11 + 3. **Script Injection** - `seams-client.js` is injected into proxied pages 12 + 13 + The user's browser does all the heavy lifting - the server just adds CORS headers. 14 + 15 + ## Setup 16 + 17 + ```bash 18 + # Install dependencies 19 + npm install 20 + 21 + # Also install cors-proxy dependencies 22 + cd cors-proxy && npm install && cd .. 23 + ``` 24 + 25 + ## Development 26 + 27 + ```bash 28 + # Start both servers (cors-proxy on 8082, static on 8081) 29 + npm run dev 30 + ``` 31 + 32 + Then visit: http://localhost:8081/#https://example.com 33 + 34 + ## How It Works 35 + 36 + 1. User visits `http://localhost:8081/#https://example.com` 37 + 2. `loadwabac.js` registers the wabac.js service worker 38 + 3. Service worker intercepts requests to `/w/liveproxy/mp_/https://example.com` 39 + 4. Requests are routed through `http://localhost:8082/proxy/https://example.com` 40 + 5. CORS proxy fetches the page and adds necessary headers 41 + 6. `seams-client.js` is injected into the page for annotation functionality 42 + 43 + ## Directory Structure 44 + 45 + ``` 46 + sure-client-proxy/ 47 + ├── cors-proxy/ 48 + │ ├── index.ts # Hono-based CORS proxy server 49 + │ ├── package.json 50 + │ └── tsconfig.json 51 + 52 + ├── static/ 53 + │ ├── index.html # Main page with iframe 54 + │ ├── loadwabac.js # Initialize wabac.js service worker 55 + │ ├── seams-client.js # Injected into proxied pages 56 + │ └── sw.js # wabac.js service worker (copied from npm) 57 + 58 + ├── package.json 59 + └── README.md 60 + ``` 61 + 62 + ## Ports 63 + 64 + - **8081** - Static site (main page with iframe) 65 + - **8082** - CORS proxy server 66 + 67 + ## Testing 68 + 69 + After running `npm run dev`: 70 + 71 + 1. Open http://localhost:8081/#https://example.com 72 + 2. Open browser DevTools console 73 + 3. Should see `[seams-client] Injected! URL: https://example.com` in the console 74 + 4. The example.com page should render in the iframe 75 + 76 + ## CORS Proxy Details 77 + 78 + The CORS proxy handles: 79 + 80 + - **Redirects**: Returns 200 with `x-redirect-status`, `x-orig-location` headers 81 + - **Cookies**: Proxies via `x-proxy-cookie` and `x-proxy-set-cookie` headers 82 + - **Referer**: Accepts `x-proxy-referer` header 83 + - **User-Agent**: Accepts `x-proxy-user-agent` header 84 + 85 + ## Next Steps 86 + 87 + 1. Replace `seams-client.js` placeholder with build from `entrypoints/via-client/main.ts` 88 + 2. Deploy CORS proxy to Cloudflare Workers or similar edge runtime 89 + 3. Deploy static site to CDN
+234
sure-client-proxy/cors-proxy/index.ts
··· 1 + import { Hono } from 'hono'; 2 + import { serve } from '@hono/node-server'; 3 + 4 + const app = new Hono(); 5 + 6 + // Allowed origins for CORS (configurable via environment variable) 7 + // Note: Use 127.0.0.1 for local dev (RFC 8252 requires loopback IP for OAuth) 8 + const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS 9 + ? process.env.CORS_ALLOWED_ORIGINS.split(',').map(s => s.trim()) 10 + : [ 11 + 'http://127.0.0.1:8081', 12 + ]; 13 + 14 + // Headers to skip when proxying request 15 + const SKIP_REQUEST_HEADERS = new Set([ 16 + 'host', 17 + 'connection', 18 + 'x-proxy-referer', 19 + 'x-proxy-cookie', 20 + 'x-proxy-user-agent', 21 + ]); 22 + 23 + // Headers to skip when returning response 24 + const SKIP_RESPONSE_HEADERS = new Set([ 25 + 'transfer-encoding', 26 + 'content-encoding', 27 + 'content-length', 28 + // Frame-busting headers - we need to strip these for iframe embedding 29 + 'x-frame-options', 30 + 'content-security-policy', 31 + 'content-security-policy-report-only', 32 + // Other security headers that might interfere 33 + 'cross-origin-opener-policy', 34 + 'cross-origin-embedder-policy', 35 + 'cross-origin-resource-policy', 36 + ]); 37 + 38 + // Handle CORS preflight 39 + app.options('/proxy/*', (c) => { 40 + const origin = c.req.header('Origin'); 41 + const method = c.req.header('Access-Control-Request-Method'); 42 + const headers = c.req.header('Access-Control-Request-Headers'); 43 + 44 + if (CORS_ALLOWED_ORIGINS.length && origin && !CORS_ALLOWED_ORIGINS.includes(origin)) { 45 + return c.json({ error: 'origin not allowed' }, 403); 46 + } 47 + 48 + if (origin && method && headers) { 49 + return new Response(null, { 50 + headers: { 51 + 'Access-Control-Allow-Method': method, 52 + 'Access-Control-Allow-Headers': headers, 53 + 'Access-Control-Allow-Origin': origin, 54 + 'Access-Control-Allow-Credentials': 'true', 55 + }, 56 + }); 57 + } 58 + 59 + return new Response(null, { 60 + headers: { 61 + 'Allow': 'GET, HEAD, POST, OPTIONS', 62 + }, 63 + }); 64 + }); 65 + 66 + // Main proxy handler 67 + app.all('/proxy/*', async (c) => { 68 + // Extract the target URL from the path 69 + let proxyUrl = c.req.path.slice('/proxy/'.length); 70 + 71 + // Handle query string 72 + const queryString = new URL(c.req.url).search; 73 + if (queryString) { 74 + proxyUrl += queryString; 75 + } 76 + 77 + // Handle protocol-relative URLs 78 + if (proxyUrl.startsWith('//')) { 79 + proxyUrl = 'https:' + proxyUrl; 80 + } 81 + 82 + // Validate URL 83 + try { 84 + new URL(proxyUrl); 85 + } catch { 86 + return c.json({ error: 'Invalid URL' }, 400); 87 + } 88 + 89 + console.log(`[cors-proxy] Proxying: ${proxyUrl}`); 90 + 91 + // Build proxy request headers 92 + const proxyHeaders = new Headers(); 93 + 94 + for (const [name, value] of c.req.raw.headers) { 95 + const lowerName = name.toLowerCase(); 96 + 97 + // Skip certain headers 98 + if (SKIP_REQUEST_HEADERS.has(lowerName) || lowerName.startsWith('cf-') || lowerName.startsWith('x-pywb-')) { 99 + continue; 100 + } 101 + 102 + proxyHeaders.set(name, value); 103 + } 104 + 105 + // Handle referer 106 + const referrer = c.req.header('x-proxy-referer'); 107 + if (referrer) { 108 + proxyHeaders.set('Referer', referrer); 109 + try { 110 + const refOrigin = new URL(referrer).origin; 111 + const targetOrigin = new URL(proxyUrl).origin; 112 + if (refOrigin !== targetOrigin) { 113 + proxyHeaders.set('Origin', refOrigin); 114 + proxyHeaders.set('Sec-Fetch-Site', 'cross-origin'); 115 + } else { 116 + proxyHeaders.delete('Origin'); 117 + proxyHeaders.set('Sec-Fetch-Site', 'same-origin'); 118 + } 119 + } catch { 120 + // Ignore invalid referrer 121 + } 122 + } else { 123 + proxyHeaders.delete('Origin'); 124 + proxyHeaders.delete('Referer'); 125 + } 126 + 127 + // Handle custom user agent 128 + const ua = c.req.header('x-proxy-user-agent'); 129 + if (ua) { 130 + proxyHeaders.set('User-Agent', ua); 131 + } 132 + 133 + // Handle cookies 134 + const cookie = c.req.header('x-proxy-cookie'); 135 + if (cookie) { 136 + proxyHeaders.set('Cookie', cookie); 137 + } 138 + 139 + // Get request body for non-GET/HEAD requests 140 + const method = c.req.method; 141 + const body = (method === 'GET' || method === 'HEAD') ? null : await c.req.raw.body; 142 + 143 + try { 144 + // Fetch with redirect: manual to handle redirects specially 145 + const resp = await fetch(proxyUrl, { 146 + method, 147 + headers: proxyHeaders, 148 + body, 149 + redirect: 'manual', 150 + }); 151 + 152 + // Build response headers 153 + const responseHeaders = new Headers(); 154 + const exposeHeaders: string[] = [ 155 + 'x-redirect-status', 156 + 'x-redirect-statusText', 157 + 'x-proxy-set-cookie', 158 + 'x-orig-location', 159 + 'x-orig-ts', 160 + ]; 161 + 162 + for (const [name, value] of resp.headers) { 163 + const lowerName = name.toLowerCase(); 164 + if (!SKIP_RESPONSE_HEADERS.has(lowerName)) { 165 + responseHeaders.set(name, value); 166 + exposeHeaders.push(name); 167 + } 168 + } 169 + 170 + // Handle set-cookie 171 + const setCookie = resp.headers.get('set-cookie'); 172 + if (setCookie) { 173 + responseHeaders.set('X-Proxy-Set-Cookie', setCookie); 174 + } 175 + 176 + // Handle redirects specially 177 + let status: number; 178 + const statusText = resp.statusText; 179 + 180 + if ([301, 302, 303, 307, 308].includes(resp.status)) { 181 + responseHeaders.set('x-redirect-status', String(resp.status)); 182 + responseHeaders.set('x-redirect-statusText', resp.statusText); 183 + 184 + const location = resp.headers.get('location'); 185 + if (location) { 186 + responseHeaders.set('x-orig-location', location); 187 + } 188 + 189 + // Return 200 so browser doesn't follow redirect 190 + status = 200; 191 + } else { 192 + status = resp.status; 193 + } 194 + 195 + // Add CORS headers 196 + const origin = c.req.header('Origin'); 197 + if (origin) { 198 + responseHeaders.set('Access-Control-Allow-Origin', origin); 199 + responseHeaders.set('Access-Control-Allow-Credentials', 'true'); 200 + responseHeaders.set('Access-Control-Expose-Headers', exposeHeaders.join(',')); 201 + } 202 + 203 + // Handle error status codes 204 + let responseBody: ReadableStream<Uint8Array> | string | null; 205 + if (status > 400 && status !== 404 && !resp.headers.get('memento-datetime')) { 206 + responseBody = `Sorry, this page could not be loaded (Error Status: ${status})`; 207 + } else { 208 + responseBody = resp.body; 209 + } 210 + 211 + return new Response(responseBody, { 212 + headers: responseHeaders, 213 + status, 214 + statusText, 215 + }); 216 + } catch (error) { 217 + console.error('[cors-proxy] Fetch error:', error); 218 + return c.json({ error: 'Failed to fetch target URL' }, 502); 219 + } 220 + }); 221 + 222 + // Health check 223 + app.get('/', (c) => { 224 + return c.json({ status: 'ok', service: 'seams-cors-proxy' }); 225 + }); 226 + 227 + const port = parseInt(process.env.CORS_PROXY_PORT || '8082', 10); 228 + console.log(`[cors-proxy] Starting server on http://localhost:${port}`); 229 + console.log(`[cors-proxy] Allowed origins: ${CORS_ALLOWED_ORIGINS.join(', ')}`); 230 + 231 + serve({ 232 + fetch: app.fetch, 233 + port, 234 + });
+613
sure-client-proxy/cors-proxy/package-lock.json
··· 1 + { 2 + "name": "seams-cors-proxy", 3 + "lockfileVersion": 3, 4 + "requires": true, 5 + "packages": { 6 + "": { 7 + "name": "seams-cors-proxy", 8 + "dependencies": { 9 + "@hono/node-server": "^1.13.0", 10 + "hono": "^4.0.0" 11 + }, 12 + "devDependencies": { 13 + "@types/node": "^20.0.0", 14 + "tsx": "^4.0.0", 15 + "typescript": "^5.0.0" 16 + } 17 + }, 18 + "node_modules/@esbuild/aix-ppc64": { 19 + "version": "0.27.2", 20 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", 21 + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", 22 + "cpu": [ 23 + "ppc64" 24 + ], 25 + "dev": true, 26 + "license": "MIT", 27 + "optional": true, 28 + "os": [ 29 + "aix" 30 + ], 31 + "engines": { 32 + "node": ">=18" 33 + } 34 + }, 35 + "node_modules/@esbuild/android-arm": { 36 + "version": "0.27.2", 37 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", 38 + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", 39 + "cpu": [ 40 + "arm" 41 + ], 42 + "dev": true, 43 + "license": "MIT", 44 + "optional": true, 45 + "os": [ 46 + "android" 47 + ], 48 + "engines": { 49 + "node": ">=18" 50 + } 51 + }, 52 + "node_modules/@esbuild/android-arm64": { 53 + "version": "0.27.2", 54 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", 55 + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", 56 + "cpu": [ 57 + "arm64" 58 + ], 59 + "dev": true, 60 + "license": "MIT", 61 + "optional": true, 62 + "os": [ 63 + "android" 64 + ], 65 + "engines": { 66 + "node": ">=18" 67 + } 68 + }, 69 + "node_modules/@esbuild/android-x64": { 70 + "version": "0.27.2", 71 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", 72 + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", 73 + "cpu": [ 74 + "x64" 75 + ], 76 + "dev": true, 77 + "license": "MIT", 78 + "optional": true, 79 + "os": [ 80 + "android" 81 + ], 82 + "engines": { 83 + "node": ">=18" 84 + } 85 + }, 86 + "node_modules/@esbuild/darwin-arm64": { 87 + "version": "0.27.2", 88 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", 89 + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", 90 + "cpu": [ 91 + "arm64" 92 + ], 93 + "dev": true, 94 + "license": "MIT", 95 + "optional": true, 96 + "os": [ 97 + "darwin" 98 + ], 99 + "engines": { 100 + "node": ">=18" 101 + } 102 + }, 103 + "node_modules/@esbuild/darwin-x64": { 104 + "version": "0.27.2", 105 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", 106 + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", 107 + "cpu": [ 108 + "x64" 109 + ], 110 + "dev": true, 111 + "license": "MIT", 112 + "optional": true, 113 + "os": [ 114 + "darwin" 115 + ], 116 + "engines": { 117 + "node": ">=18" 118 + } 119 + }, 120 + "node_modules/@esbuild/freebsd-arm64": { 121 + "version": "0.27.2", 122 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", 123 + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", 124 + "cpu": [ 125 + "arm64" 126 + ], 127 + "dev": true, 128 + "license": "MIT", 129 + "optional": true, 130 + "os": [ 131 + "freebsd" 132 + ], 133 + "engines": { 134 + "node": ">=18" 135 + } 136 + }, 137 + "node_modules/@esbuild/freebsd-x64": { 138 + "version": "0.27.2", 139 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", 140 + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", 141 + "cpu": [ 142 + "x64" 143 + ], 144 + "dev": true, 145 + "license": "MIT", 146 + "optional": true, 147 + "os": [ 148 + "freebsd" 149 + ], 150 + "engines": { 151 + "node": ">=18" 152 + } 153 + }, 154 + "node_modules/@esbuild/linux-arm": { 155 + "version": "0.27.2", 156 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", 157 + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", 158 + "cpu": [ 159 + "arm" 160 + ], 161 + "dev": true, 162 + "license": "MIT", 163 + "optional": true, 164 + "os": [ 165 + "linux" 166 + ], 167 + "engines": { 168 + "node": ">=18" 169 + } 170 + }, 171 + "node_modules/@esbuild/linux-arm64": { 172 + "version": "0.27.2", 173 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", 174 + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", 175 + "cpu": [ 176 + "arm64" 177 + ], 178 + "dev": true, 179 + "license": "MIT", 180 + "optional": true, 181 + "os": [ 182 + "linux" 183 + ], 184 + "engines": { 185 + "node": ">=18" 186 + } 187 + }, 188 + "node_modules/@esbuild/linux-ia32": { 189 + "version": "0.27.2", 190 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", 191 + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", 192 + "cpu": [ 193 + "ia32" 194 + ], 195 + "dev": true, 196 + "license": "MIT", 197 + "optional": true, 198 + "os": [ 199 + "linux" 200 + ], 201 + "engines": { 202 + "node": ">=18" 203 + } 204 + }, 205 + "node_modules/@esbuild/linux-loong64": { 206 + "version": "0.27.2", 207 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", 208 + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", 209 + "cpu": [ 210 + "loong64" 211 + ], 212 + "dev": true, 213 + "license": "MIT", 214 + "optional": true, 215 + "os": [ 216 + "linux" 217 + ], 218 + "engines": { 219 + "node": ">=18" 220 + } 221 + }, 222 + "node_modules/@esbuild/linux-mips64el": { 223 + "version": "0.27.2", 224 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", 225 + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", 226 + "cpu": [ 227 + "mips64el" 228 + ], 229 + "dev": true, 230 + "license": "MIT", 231 + "optional": true, 232 + "os": [ 233 + "linux" 234 + ], 235 + "engines": { 236 + "node": ">=18" 237 + } 238 + }, 239 + "node_modules/@esbuild/linux-ppc64": { 240 + "version": "0.27.2", 241 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", 242 + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", 243 + "cpu": [ 244 + "ppc64" 245 + ], 246 + "dev": true, 247 + "license": "MIT", 248 + "optional": true, 249 + "os": [ 250 + "linux" 251 + ], 252 + "engines": { 253 + "node": ">=18" 254 + } 255 + }, 256 + "node_modules/@esbuild/linux-riscv64": { 257 + "version": "0.27.2", 258 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", 259 + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", 260 + "cpu": [ 261 + "riscv64" 262 + ], 263 + "dev": true, 264 + "license": "MIT", 265 + "optional": true, 266 + "os": [ 267 + "linux" 268 + ], 269 + "engines": { 270 + "node": ">=18" 271 + } 272 + }, 273 + "node_modules/@esbuild/linux-s390x": { 274 + "version": "0.27.2", 275 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", 276 + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", 277 + "cpu": [ 278 + "s390x" 279 + ], 280 + "dev": true, 281 + "license": "MIT", 282 + "optional": true, 283 + "os": [ 284 + "linux" 285 + ], 286 + "engines": { 287 + "node": ">=18" 288 + } 289 + }, 290 + "node_modules/@esbuild/linux-x64": { 291 + "version": "0.27.2", 292 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", 293 + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", 294 + "cpu": [ 295 + "x64" 296 + ], 297 + "dev": true, 298 + "license": "MIT", 299 + "optional": true, 300 + "os": [ 301 + "linux" 302 + ], 303 + "engines": { 304 + "node": ">=18" 305 + } 306 + }, 307 + "node_modules/@esbuild/netbsd-arm64": { 308 + "version": "0.27.2", 309 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", 310 + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", 311 + "cpu": [ 312 + "arm64" 313 + ], 314 + "dev": true, 315 + "license": "MIT", 316 + "optional": true, 317 + "os": [ 318 + "netbsd" 319 + ], 320 + "engines": { 321 + "node": ">=18" 322 + } 323 + }, 324 + "node_modules/@esbuild/netbsd-x64": { 325 + "version": "0.27.2", 326 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", 327 + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", 328 + "cpu": [ 329 + "x64" 330 + ], 331 + "dev": true, 332 + "license": "MIT", 333 + "optional": true, 334 + "os": [ 335 + "netbsd" 336 + ], 337 + "engines": { 338 + "node": ">=18" 339 + } 340 + }, 341 + "node_modules/@esbuild/openbsd-arm64": { 342 + "version": "0.27.2", 343 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", 344 + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", 345 + "cpu": [ 346 + "arm64" 347 + ], 348 + "dev": true, 349 + "license": "MIT", 350 + "optional": true, 351 + "os": [ 352 + "openbsd" 353 + ], 354 + "engines": { 355 + "node": ">=18" 356 + } 357 + }, 358 + "node_modules/@esbuild/openbsd-x64": { 359 + "version": "0.27.2", 360 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", 361 + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", 362 + "cpu": [ 363 + "x64" 364 + ], 365 + "dev": true, 366 + "license": "MIT", 367 + "optional": true, 368 + "os": [ 369 + "openbsd" 370 + ], 371 + "engines": { 372 + "node": ">=18" 373 + } 374 + }, 375 + "node_modules/@esbuild/openharmony-arm64": { 376 + "version": "0.27.2", 377 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", 378 + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", 379 + "cpu": [ 380 + "arm64" 381 + ], 382 + "dev": true, 383 + "license": "MIT", 384 + "optional": true, 385 + "os": [ 386 + "openharmony" 387 + ], 388 + "engines": { 389 + "node": ">=18" 390 + } 391 + }, 392 + "node_modules/@esbuild/sunos-x64": { 393 + "version": "0.27.2", 394 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", 395 + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", 396 + "cpu": [ 397 + "x64" 398 + ], 399 + "dev": true, 400 + "license": "MIT", 401 + "optional": true, 402 + "os": [ 403 + "sunos" 404 + ], 405 + "engines": { 406 + "node": ">=18" 407 + } 408 + }, 409 + "node_modules/@esbuild/win32-arm64": { 410 + "version": "0.27.2", 411 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", 412 + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", 413 + "cpu": [ 414 + "arm64" 415 + ], 416 + "dev": true, 417 + "license": "MIT", 418 + "optional": true, 419 + "os": [ 420 + "win32" 421 + ], 422 + "engines": { 423 + "node": ">=18" 424 + } 425 + }, 426 + "node_modules/@esbuild/win32-ia32": { 427 + "version": "0.27.2", 428 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", 429 + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", 430 + "cpu": [ 431 + "ia32" 432 + ], 433 + "dev": true, 434 + "license": "MIT", 435 + "optional": true, 436 + "os": [ 437 + "win32" 438 + ], 439 + "engines": { 440 + "node": ">=18" 441 + } 442 + }, 443 + "node_modules/@esbuild/win32-x64": { 444 + "version": "0.27.2", 445 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", 446 + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", 447 + "cpu": [ 448 + "x64" 449 + ], 450 + "dev": true, 451 + "license": "MIT", 452 + "optional": true, 453 + "os": [ 454 + "win32" 455 + ], 456 + "engines": { 457 + "node": ">=18" 458 + } 459 + }, 460 + "node_modules/@hono/node-server": { 461 + "version": "1.19.7", 462 + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz", 463 + "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==", 464 + "license": "MIT", 465 + "engines": { 466 + "node": ">=18.14.1" 467 + }, 468 + "peerDependencies": { 469 + "hono": "^4" 470 + } 471 + }, 472 + "node_modules/@types/node": { 473 + "version": "20.19.27", 474 + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", 475 + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", 476 + "dev": true, 477 + "license": "MIT", 478 + "dependencies": { 479 + "undici-types": "~6.21.0" 480 + } 481 + }, 482 + "node_modules/esbuild": { 483 + "version": "0.27.2", 484 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", 485 + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", 486 + "dev": true, 487 + "hasInstallScript": true, 488 + "license": "MIT", 489 + "bin": { 490 + "esbuild": "bin/esbuild" 491 + }, 492 + "engines": { 493 + "node": ">=18" 494 + }, 495 + "optionalDependencies": { 496 + "@esbuild/aix-ppc64": "0.27.2", 497 + "@esbuild/android-arm": "0.27.2", 498 + "@esbuild/android-arm64": "0.27.2", 499 + "@esbuild/android-x64": "0.27.2", 500 + "@esbuild/darwin-arm64": "0.27.2", 501 + "@esbuild/darwin-x64": "0.27.2", 502 + "@esbuild/freebsd-arm64": "0.27.2", 503 + "@esbuild/freebsd-x64": "0.27.2", 504 + "@esbuild/linux-arm": "0.27.2", 505 + "@esbuild/linux-arm64": "0.27.2", 506 + "@esbuild/linux-ia32": "0.27.2", 507 + "@esbuild/linux-loong64": "0.27.2", 508 + "@esbuild/linux-mips64el": "0.27.2", 509 + "@esbuild/linux-ppc64": "0.27.2", 510 + "@esbuild/linux-riscv64": "0.27.2", 511 + "@esbuild/linux-s390x": "0.27.2", 512 + "@esbuild/linux-x64": "0.27.2", 513 + "@esbuild/netbsd-arm64": "0.27.2", 514 + "@esbuild/netbsd-x64": "0.27.2", 515 + "@esbuild/openbsd-arm64": "0.27.2", 516 + "@esbuild/openbsd-x64": "0.27.2", 517 + "@esbuild/openharmony-arm64": "0.27.2", 518 + "@esbuild/sunos-x64": "0.27.2", 519 + "@esbuild/win32-arm64": "0.27.2", 520 + "@esbuild/win32-ia32": "0.27.2", 521 + "@esbuild/win32-x64": "0.27.2" 522 + } 523 + }, 524 + "node_modules/fsevents": { 525 + "version": "2.3.3", 526 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 527 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 528 + "dev": true, 529 + "hasInstallScript": true, 530 + "license": "MIT", 531 + "optional": true, 532 + "os": [ 533 + "darwin" 534 + ], 535 + "engines": { 536 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 537 + } 538 + }, 539 + "node_modules/get-tsconfig": { 540 + "version": "4.13.0", 541 + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", 542 + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", 543 + "dev": true, 544 + "license": "MIT", 545 + "dependencies": { 546 + "resolve-pkg-maps": "^1.0.0" 547 + }, 548 + "funding": { 549 + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 550 + } 551 + }, 552 + "node_modules/hono": { 553 + "version": "4.11.2", 554 + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.2.tgz", 555 + "integrity": "sha512-o+avdUAD1v94oHkjGBhiMhBV4WBHxhbu0+CUVH78hhphKy/OKQLxtKjkmmNcrMlbYAhAbsM/9F+l3KnYxyD3Lg==", 556 + "license": "MIT", 557 + "engines": { 558 + "node": ">=16.9.0" 559 + } 560 + }, 561 + "node_modules/resolve-pkg-maps": { 562 + "version": "1.0.0", 563 + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 564 + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 565 + "dev": true, 566 + "license": "MIT", 567 + "funding": { 568 + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 569 + } 570 + }, 571 + "node_modules/tsx": { 572 + "version": "4.21.0", 573 + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", 574 + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", 575 + "dev": true, 576 + "license": "MIT", 577 + "dependencies": { 578 + "esbuild": "~0.27.0", 579 + "get-tsconfig": "^4.7.5" 580 + }, 581 + "bin": { 582 + "tsx": "dist/cli.mjs" 583 + }, 584 + "engines": { 585 + "node": ">=18.0.0" 586 + }, 587 + "optionalDependencies": { 588 + "fsevents": "~2.3.3" 589 + } 590 + }, 591 + "node_modules/typescript": { 592 + "version": "5.9.3", 593 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 594 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 595 + "dev": true, 596 + "license": "Apache-2.0", 597 + "bin": { 598 + "tsc": "bin/tsc", 599 + "tsserver": "bin/tsserver" 600 + }, 601 + "engines": { 602 + "node": ">=14.17" 603 + } 604 + }, 605 + "node_modules/undici-types": { 606 + "version": "6.21.0", 607 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 608 + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 609 + "dev": true, 610 + "license": "MIT" 611 + } 612 + } 613 + }
+18
sure-client-proxy/cors-proxy/package.json
··· 1 + { 2 + "name": "seams-cors-proxy", 3 + "type": "module", 4 + "scripts": { 5 + "dev": "tsx watch index.ts", 6 + "start": "tsx index.ts", 7 + "build": "tsc" 8 + }, 9 + "dependencies": { 10 + "hono": "^4.0.0", 11 + "@hono/node-server": "^1.13.0" 12 + }, 13 + "devDependencies": { 14 + "tsx": "^4.0.0", 15 + "@types/node": "^20.0.0", 16 + "typescript": "^5.0.0" 17 + } 18 + }
+13
sure-client-proxy/cors-proxy/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "target": "ES2020", 4 + "module": "ESNext", 5 + "moduleResolution": "bundler", 6 + "strict": true, 7 + "esModuleInterop": true, 8 + "skipLibCheck": true, 9 + "outDir": "./dist", 10 + "rootDir": "." 11 + }, 12 + "include": ["*.ts"] 13 + }
+77
sure-client-proxy/html/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 + :root { 9 + --forest-green: #2d5016; 10 + } 11 + * { 12 + box-sizing: border-box; 13 + margin: 0; 14 + padding: 0; 15 + } 16 + body { 17 + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 18 + display: flex; 19 + align-items: center; 20 + justify-content: center; 21 + height: 100vh; 22 + margin: 0; 23 + overflow: hidden; 24 + background: #fafafa; 25 + } 26 + .callback-container { 27 + background: white; 28 + padding: 48px; 29 + border: 2px dashed #d0d0d0; 30 + border-radius: 2px; 31 + text-align: center; 32 + max-width: 400px; 33 + width: 90%; 34 + box-shadow: 0 4px 12px rgba(45, 80, 22, 0.05); 35 + } 36 + .logo { 37 + font-size: 16px; 38 + font-weight: 700; 39 + letter-spacing: 0.1em; 40 + text-transform: uppercase; 41 + color: #666; 42 + margin-bottom: 16px; 43 + } 44 + h2 { 45 + font-size: 24px; 46 + color: #1a1a1a; 47 + margin-bottom: 16px; 48 + } 49 + .spinner { 50 + border: 3px solid #f3f3f3; 51 + border-top: 3px solid var(--forest-green); 52 + border-radius: 50%; 53 + width: 32px; 54 + height: 32px; 55 + animation: spin 1s linear infinite; 56 + margin: 0 auto 24px; 57 + } 58 + @keyframes spin { 59 + 0% { transform: rotate(0deg); } 60 + 100% { transform: rotate(360deg); } 61 + } 62 + #status { 63 + color: #666; 64 + font-size: 14px; 65 + } 66 + </style> 67 + </head> 68 + <body> 69 + <div class="callback-container"> 70 + <div class="logo">Seams</div> 71 + <div class="spinner"></div> 72 + <h2>Connecting...</h2> 73 + <p id="status">Completing authentication</p> 74 + </div> 75 + <script type="module" src="../../entrypoints/via-client/oauth-callback.ts"></script> 76 + </body> 77 + </html>
+12
sure-client-proxy/html/seams-shell.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 Shell</title> 7 + </head> 8 + <body> 9 + <!-- Shell script - manages BackgroundWorker and message routing --> 10 + <script type="module" src="../../entrypoints/via-client/shell.ts"></script> 11 + </body> 12 + </html>
+2093
sure-client-proxy/package-lock.json
··· 1 + { 2 + "name": "sure-client-proxy", 3 + "lockfileVersion": 3, 4 + "requires": true, 5 + "packages": { 6 + "": { 7 + "name": "sure-client-proxy", 8 + "hasInstallScript": true, 9 + "dependencies": { 10 + "@webrecorder/wabac": "^2.20.0" 11 + }, 12 + "devDependencies": { 13 + "concurrently": "^8.0.0", 14 + "serve": "^14.0.0" 15 + } 16 + }, 17 + "node_modules/@babel/runtime": { 18 + "version": "7.28.4", 19 + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", 20 + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", 21 + "dev": true, 22 + "license": "MIT", 23 + "engines": { 24 + "node": ">=6.9.0" 25 + } 26 + }, 27 + "node_modules/@peculiar/asn1-cms": { 28 + "version": "2.6.0", 29 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.0.tgz", 30 + "integrity": "sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==", 31 + "license": "MIT", 32 + "dependencies": { 33 + "@peculiar/asn1-schema": "^2.6.0", 34 + "@peculiar/asn1-x509": "^2.6.0", 35 + "@peculiar/asn1-x509-attr": "^2.6.0", 36 + "asn1js": "^3.0.6", 37 + "tslib": "^2.8.1" 38 + } 39 + }, 40 + "node_modules/@peculiar/asn1-csr": { 41 + "version": "2.6.0", 42 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.0.tgz", 43 + "integrity": "sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==", 44 + "license": "MIT", 45 + "dependencies": { 46 + "@peculiar/asn1-schema": "^2.6.0", 47 + "@peculiar/asn1-x509": "^2.6.0", 48 + "asn1js": "^3.0.6", 49 + "tslib": "^2.8.1" 50 + } 51 + }, 52 + "node_modules/@peculiar/asn1-ecc": { 53 + "version": "2.6.0", 54 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.0.tgz", 55 + "integrity": "sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==", 56 + "license": "MIT", 57 + "dependencies": { 58 + "@peculiar/asn1-schema": "^2.6.0", 59 + "@peculiar/asn1-x509": "^2.6.0", 60 + "asn1js": "^3.0.6", 61 + "tslib": "^2.8.1" 62 + } 63 + }, 64 + "node_modules/@peculiar/asn1-pfx": { 65 + "version": "2.6.0", 66 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.0.tgz", 67 + "integrity": "sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==", 68 + "license": "MIT", 69 + "dependencies": { 70 + "@peculiar/asn1-cms": "^2.6.0", 71 + "@peculiar/asn1-pkcs8": "^2.6.0", 72 + "@peculiar/asn1-rsa": "^2.6.0", 73 + "@peculiar/asn1-schema": "^2.6.0", 74 + "asn1js": "^3.0.6", 75 + "tslib": "^2.8.1" 76 + } 77 + }, 78 + "node_modules/@peculiar/asn1-pkcs8": { 79 + "version": "2.6.0", 80 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.0.tgz", 81 + "integrity": "sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==", 82 + "license": "MIT", 83 + "dependencies": { 84 + "@peculiar/asn1-schema": "^2.6.0", 85 + "@peculiar/asn1-x509": "^2.6.0", 86 + "asn1js": "^3.0.6", 87 + "tslib": "^2.8.1" 88 + } 89 + }, 90 + "node_modules/@peculiar/asn1-pkcs9": { 91 + "version": "2.6.0", 92 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.0.tgz", 93 + "integrity": "sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==", 94 + "license": "MIT", 95 + "dependencies": { 96 + "@peculiar/asn1-cms": "^2.6.0", 97 + "@peculiar/asn1-pfx": "^2.6.0", 98 + "@peculiar/asn1-pkcs8": "^2.6.0", 99 + "@peculiar/asn1-schema": "^2.6.0", 100 + "@peculiar/asn1-x509": "^2.6.0", 101 + "@peculiar/asn1-x509-attr": "^2.6.0", 102 + "asn1js": "^3.0.6", 103 + "tslib": "^2.8.1" 104 + } 105 + }, 106 + "node_modules/@peculiar/asn1-rsa": { 107 + "version": "2.6.0", 108 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.0.tgz", 109 + "integrity": "sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==", 110 + "license": "MIT", 111 + "dependencies": { 112 + "@peculiar/asn1-schema": "^2.6.0", 113 + "@peculiar/asn1-x509": "^2.6.0", 114 + "asn1js": "^3.0.6", 115 + "tslib": "^2.8.1" 116 + } 117 + }, 118 + "node_modules/@peculiar/asn1-schema": { 119 + "version": "2.6.0", 120 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", 121 + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", 122 + "license": "MIT", 123 + "dependencies": { 124 + "asn1js": "^3.0.6", 125 + "pvtsutils": "^1.3.6", 126 + "tslib": "^2.8.1" 127 + } 128 + }, 129 + "node_modules/@peculiar/asn1-x509": { 130 + "version": "2.6.0", 131 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.0.tgz", 132 + "integrity": "sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==", 133 + "license": "MIT", 134 + "dependencies": { 135 + "@peculiar/asn1-schema": "^2.6.0", 136 + "asn1js": "^3.0.6", 137 + "pvtsutils": "^1.3.6", 138 + "tslib": "^2.8.1" 139 + } 140 + }, 141 + "node_modules/@peculiar/asn1-x509-attr": { 142 + "version": "2.6.0", 143 + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.0.tgz", 144 + "integrity": "sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==", 145 + "license": "MIT", 146 + "dependencies": { 147 + "@peculiar/asn1-schema": "^2.6.0", 148 + "@peculiar/asn1-x509": "^2.6.0", 149 + "asn1js": "^3.0.6", 150 + "tslib": "^2.8.1" 151 + } 152 + }, 153 + "node_modules/@peculiar/x509": { 154 + "version": "1.14.2", 155 + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.2.tgz", 156 + "integrity": "sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==", 157 + "license": "MIT", 158 + "dependencies": { 159 + "@peculiar/asn1-cms": "^2.6.0", 160 + "@peculiar/asn1-csr": "^2.6.0", 161 + "@peculiar/asn1-ecc": "^2.6.0", 162 + "@peculiar/asn1-pkcs9": "^2.6.0", 163 + "@peculiar/asn1-rsa": "^2.6.0", 164 + "@peculiar/asn1-schema": "^2.6.0", 165 + "@peculiar/asn1-x509": "^2.6.0", 166 + "pvtsutils": "^1.3.6", 167 + "reflect-metadata": "^0.2.2", 168 + "tslib": "^2.8.1", 169 + "tsyringe": "^4.10.0" 170 + }, 171 + "engines": { 172 + "node": ">=22.0.0" 173 + } 174 + }, 175 + "node_modules/@types/js-levenshtein": { 176 + "version": "1.1.3", 177 + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", 178 + "integrity": "sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==", 179 + "license": "MIT" 180 + }, 181 + "node_modules/@types/node": { 182 + "version": "25.0.3", 183 + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", 184 + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", 185 + "license": "MIT", 186 + "dependencies": { 187 + "undici-types": "~7.16.0" 188 + } 189 + }, 190 + "node_modules/@types/pako": { 191 + "version": "1.0.7", 192 + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.7.tgz", 193 + "integrity": "sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A==", 194 + "license": "MIT" 195 + }, 196 + "node_modules/@types/stream-buffers": { 197 + "version": "3.0.8", 198 + "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.8.tgz", 199 + "integrity": "sha512-J+7VaHKNvlNPJPEJXX/fKa9DZtR/xPMwuIbe+yNOwp1YB+ApUOBv2aUpEoBJEi8nJgbgs1x8e73ttg0r1rSUdw==", 200 + "license": "MIT", 201 + "dependencies": { 202 + "@types/node": "*" 203 + } 204 + }, 205 + "node_modules/@webrecorder/wabac": { 206 + "version": "2.25.2", 207 + "resolved": "https://registry.npmjs.org/@webrecorder/wabac/-/wabac-2.25.2.tgz", 208 + "integrity": "sha512-leu+GmHYlzNFeIjnOhuAi0dUYyYquaHFyUatve8oPGhQUHG4jmO9ijydq8t71i90Rs01aEsNV3N7+je4CFLIhg==", 209 + "license": "AGPL-3.0-or-later", 210 + "dependencies": { 211 + "@peculiar/asn1-ecc": "^2.3.4", 212 + "@peculiar/asn1-schema": "^2.3.3", 213 + "@peculiar/x509": "^1.9.2", 214 + "@types/js-levenshtein": "^1.1.3", 215 + "@webrecorder/wombat": "^3.10.3", 216 + "acorn": "^8.15.0", 217 + "auto-js-ipfs": "^2.1.1", 218 + "base64-js": "^1.5.1", 219 + "brotli": "^1.3.3", 220 + "buffer": "^6.0.3", 221 + "fast-xml-parser": "^4.4.1", 222 + "hash-wasm": "^4.9.0", 223 + "http-status-codes": "^2.1.4", 224 + "idb": "^7.1.1", 225 + "js-levenshtein": "^1.1.6", 226 + "js-yaml": "^4.1.1", 227 + "mime": "^4.1.0", 228 + "pako": "^1.0.11", 229 + "parse5-html-rewriting-stream": "^7.0.0", 230 + "parse5-sax-parser": "^7.0.0", 231 + "path-parser": "^6.1.0", 232 + "process": "^0.11.10", 233 + "stream-browserify": "^3.0.0", 234 + "warcio": "^2.4.7" 235 + } 236 + }, 237 + "node_modules/@webrecorder/wombat": { 238 + "version": "3.10.3", 239 + "resolved": "https://registry.npmjs.org/@webrecorder/wombat/-/wombat-3.10.3.tgz", 240 + "integrity": "sha512-tg1zRFlWUcYBsSMFCNf4zprCxlRfLmd7DnGsufRHS8fX0aJAMU3jNSE00Q9pWTcdIsxXQCNk4OT9FTlErCxRrg==", 241 + "license": "AGPL-3.0-or-later", 242 + "dependencies": { 243 + "warcio": "^2.4.7" 244 + } 245 + }, 246 + "node_modules/@zeit/schemas": { 247 + "version": "2.36.0", 248 + "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.36.0.tgz", 249 + "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", 250 + "dev": true, 251 + "license": "MIT" 252 + }, 253 + "node_modules/acorn": { 254 + "version": "8.15.0", 255 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", 256 + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", 257 + "license": "MIT", 258 + "bin": { 259 + "acorn": "bin/acorn" 260 + }, 261 + "engines": { 262 + "node": ">=0.4.0" 263 + } 264 + }, 265 + "node_modules/ajv": { 266 + "version": "8.12.0", 267 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", 268 + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", 269 + "dev": true, 270 + "license": "MIT", 271 + "dependencies": { 272 + "fast-deep-equal": "^3.1.1", 273 + "json-schema-traverse": "^1.0.0", 274 + "require-from-string": "^2.0.2", 275 + "uri-js": "^4.2.2" 276 + }, 277 + "funding": { 278 + "type": "github", 279 + "url": "https://github.com/sponsors/epoberezkin" 280 + } 281 + }, 282 + "node_modules/ansi-align": { 283 + "version": "3.0.1", 284 + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", 285 + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", 286 + "dev": true, 287 + "license": "ISC", 288 + "dependencies": { 289 + "string-width": "^4.1.0" 290 + } 291 + }, 292 + "node_modules/ansi-align/node_modules/ansi-regex": { 293 + "version": "5.0.1", 294 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 295 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 296 + "dev": true, 297 + "license": "MIT", 298 + "engines": { 299 + "node": ">=8" 300 + } 301 + }, 302 + "node_modules/ansi-align/node_modules/emoji-regex": { 303 + "version": "8.0.0", 304 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 305 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 306 + "dev": true, 307 + "license": "MIT" 308 + }, 309 + "node_modules/ansi-align/node_modules/string-width": { 310 + "version": "4.2.3", 311 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 312 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 313 + "dev": true, 314 + "license": "MIT", 315 + "dependencies": { 316 + "emoji-regex": "^8.0.0", 317 + "is-fullwidth-code-point": "^3.0.0", 318 + "strip-ansi": "^6.0.1" 319 + }, 320 + "engines": { 321 + "node": ">=8" 322 + } 323 + }, 324 + "node_modules/ansi-align/node_modules/strip-ansi": { 325 + "version": "6.0.1", 326 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 327 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 328 + "dev": true, 329 + "license": "MIT", 330 + "dependencies": { 331 + "ansi-regex": "^5.0.1" 332 + }, 333 + "engines": { 334 + "node": ">=8" 335 + } 336 + }, 337 + "node_modules/ansi-regex": { 338 + "version": "6.2.2", 339 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", 340 + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", 341 + "dev": true, 342 + "license": "MIT", 343 + "engines": { 344 + "node": ">=12" 345 + }, 346 + "funding": { 347 + "url": "https://github.com/chalk/ansi-regex?sponsor=1" 348 + } 349 + }, 350 + "node_modules/ansi-styles": { 351 + "version": "4.3.0", 352 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 353 + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 354 + "license": "MIT", 355 + "dependencies": { 356 + "color-convert": "^2.0.1" 357 + }, 358 + "engines": { 359 + "node": ">=8" 360 + }, 361 + "funding": { 362 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 363 + } 364 + }, 365 + "node_modules/arch": { 366 + "version": "2.2.0", 367 + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", 368 + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", 369 + "dev": true, 370 + "funding": [ 371 + { 372 + "type": "github", 373 + "url": "https://github.com/sponsors/feross" 374 + }, 375 + { 376 + "type": "patreon", 377 + "url": "https://www.patreon.com/feross" 378 + }, 379 + { 380 + "type": "consulting", 381 + "url": "https://feross.org/support" 382 + } 383 + ], 384 + "license": "MIT" 385 + }, 386 + "node_modules/arg": { 387 + "version": "5.0.2", 388 + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 389 + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 390 + "dev": true, 391 + "license": "MIT" 392 + }, 393 + "node_modules/argparse": { 394 + "version": "2.0.1", 395 + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 396 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 397 + "license": "Python-2.0" 398 + }, 399 + "node_modules/asn1js": { 400 + "version": "3.0.7", 401 + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", 402 + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", 403 + "license": "BSD-3-Clause", 404 + "dependencies": { 405 + "pvtsutils": "^1.3.6", 406 + "pvutils": "^1.1.3", 407 + "tslib": "^2.8.1" 408 + }, 409 + "engines": { 410 + "node": ">=12.0.0" 411 + } 412 + }, 413 + "node_modules/auto-js-ipfs": { 414 + "version": "2.3.0", 415 + "resolved": "https://registry.npmjs.org/auto-js-ipfs/-/auto-js-ipfs-2.3.0.tgz", 416 + "integrity": "sha512-gUg2+lJqcbBUDgimlOVqWWBVl/8Avs9JMIjEpIk4liho+5hFGrCXvj1ydj5GGxpOXUGkR0H9eVxTXwu+xvQgIg==", 417 + "license": "MIT" 418 + }, 419 + "node_modules/balanced-match": { 420 + "version": "1.0.2", 421 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 422 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 423 + "dev": true, 424 + "license": "MIT" 425 + }, 426 + "node_modules/base32-encode": { 427 + "version": "2.0.0", 428 + "resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-2.0.0.tgz", 429 + "integrity": "sha512-mlmkfc2WqdDtMl/id4qm3A7RjW6jxcbAoMjdRmsPiwQP0ufD4oXItYMnPgVHe80lnAIy+1xwzhHE1s4FoIceSw==", 430 + "license": "MIT", 431 + "dependencies": { 432 + "to-data-view": "^2.0.0" 433 + }, 434 + "engines": { 435 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 436 + } 437 + }, 438 + "node_modules/base64-js": { 439 + "version": "1.5.1", 440 + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 441 + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 442 + "funding": [ 443 + { 444 + "type": "github", 445 + "url": "https://github.com/sponsors/feross" 446 + }, 447 + { 448 + "type": "patreon", 449 + "url": "https://www.patreon.com/feross" 450 + }, 451 + { 452 + "type": "consulting", 453 + "url": "https://feross.org/support" 454 + } 455 + ], 456 + "license": "MIT" 457 + }, 458 + "node_modules/boxen": { 459 + "version": "7.0.0", 460 + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", 461 + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", 462 + "dev": true, 463 + "license": "MIT", 464 + "dependencies": { 465 + "ansi-align": "^3.0.1", 466 + "camelcase": "^7.0.0", 467 + "chalk": "^5.0.1", 468 + "cli-boxes": "^3.0.0", 469 + "string-width": "^5.1.2", 470 + "type-fest": "^2.13.0", 471 + "widest-line": "^4.0.1", 472 + "wrap-ansi": "^8.0.1" 473 + }, 474 + "engines": { 475 + "node": ">=14.16" 476 + }, 477 + "funding": { 478 + "url": "https://github.com/sponsors/sindresorhus" 479 + } 480 + }, 481 + "node_modules/boxen/node_modules/chalk": { 482 + "version": "5.6.2", 483 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", 484 + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", 485 + "dev": true, 486 + "license": "MIT", 487 + "engines": { 488 + "node": "^12.17.0 || ^14.13 || >=16.0.0" 489 + }, 490 + "funding": { 491 + "url": "https://github.com/chalk/chalk?sponsor=1" 492 + } 493 + }, 494 + "node_modules/brace-expansion": { 495 + "version": "1.1.12", 496 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", 497 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", 498 + "dev": true, 499 + "license": "MIT", 500 + "dependencies": { 501 + "balanced-match": "^1.0.0", 502 + "concat-map": "0.0.1" 503 + } 504 + }, 505 + "node_modules/brotli": { 506 + "version": "1.3.3", 507 + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", 508 + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", 509 + "license": "MIT", 510 + "dependencies": { 511 + "base64-js": "^1.1.2" 512 + } 513 + }, 514 + "node_modules/buffer": { 515 + "version": "6.0.3", 516 + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 517 + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 518 + "funding": [ 519 + { 520 + "type": "github", 521 + "url": "https://github.com/sponsors/feross" 522 + }, 523 + { 524 + "type": "patreon", 525 + "url": "https://www.patreon.com/feross" 526 + }, 527 + { 528 + "type": "consulting", 529 + "url": "https://feross.org/support" 530 + } 531 + ], 532 + "license": "MIT", 533 + "dependencies": { 534 + "base64-js": "^1.3.1", 535 + "ieee754": "^1.2.1" 536 + } 537 + }, 538 + "node_modules/bytes": { 539 + "version": "3.1.2", 540 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 541 + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 542 + "dev": true, 543 + "license": "MIT", 544 + "engines": { 545 + "node": ">= 0.8" 546 + } 547 + }, 548 + "node_modules/camelcase": { 549 + "version": "7.0.1", 550 + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", 551 + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", 552 + "dev": true, 553 + "license": "MIT", 554 + "engines": { 555 + "node": ">=14.16" 556 + }, 557 + "funding": { 558 + "url": "https://github.com/sponsors/sindresorhus" 559 + } 560 + }, 561 + "node_modules/chalk": { 562 + "version": "4.1.2", 563 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 564 + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 565 + "dev": true, 566 + "license": "MIT", 567 + "dependencies": { 568 + "ansi-styles": "^4.1.0", 569 + "supports-color": "^7.1.0" 570 + }, 571 + "engines": { 572 + "node": ">=10" 573 + }, 574 + "funding": { 575 + "url": "https://github.com/chalk/chalk?sponsor=1" 576 + } 577 + }, 578 + "node_modules/chalk-template": { 579 + "version": "0.4.0", 580 + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", 581 + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", 582 + "dev": true, 583 + "license": "MIT", 584 + "dependencies": { 585 + "chalk": "^4.1.2" 586 + }, 587 + "engines": { 588 + "node": ">=12" 589 + }, 590 + "funding": { 591 + "url": "https://github.com/chalk/chalk-template?sponsor=1" 592 + } 593 + }, 594 + "node_modules/chalk/node_modules/supports-color": { 595 + "version": "7.2.0", 596 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 597 + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 598 + "dev": true, 599 + "license": "MIT", 600 + "dependencies": { 601 + "has-flag": "^4.0.0" 602 + }, 603 + "engines": { 604 + "node": ">=8" 605 + } 606 + }, 607 + "node_modules/cli-boxes": { 608 + "version": "3.0.0", 609 + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", 610 + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", 611 + "dev": true, 612 + "license": "MIT", 613 + "engines": { 614 + "node": ">=10" 615 + }, 616 + "funding": { 617 + "url": "https://github.com/sponsors/sindresorhus" 618 + } 619 + }, 620 + "node_modules/clipboardy": { 621 + "version": "3.0.0", 622 + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", 623 + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", 624 + "dev": true, 625 + "license": "MIT", 626 + "dependencies": { 627 + "arch": "^2.2.0", 628 + "execa": "^5.1.1", 629 + "is-wsl": "^2.2.0" 630 + }, 631 + "engines": { 632 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 633 + }, 634 + "funding": { 635 + "url": "https://github.com/sponsors/sindresorhus" 636 + } 637 + }, 638 + "node_modules/cliui": { 639 + "version": "8.0.1", 640 + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 641 + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 642 + "license": "ISC", 643 + "dependencies": { 644 + "string-width": "^4.2.0", 645 + "strip-ansi": "^6.0.1", 646 + "wrap-ansi": "^7.0.0" 647 + }, 648 + "engines": { 649 + "node": ">=12" 650 + } 651 + }, 652 + "node_modules/cliui/node_modules/ansi-regex": { 653 + "version": "5.0.1", 654 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 655 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 656 + "license": "MIT", 657 + "engines": { 658 + "node": ">=8" 659 + } 660 + }, 661 + "node_modules/cliui/node_modules/emoji-regex": { 662 + "version": "8.0.0", 663 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 664 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 665 + "license": "MIT" 666 + }, 667 + "node_modules/cliui/node_modules/string-width": { 668 + "version": "4.2.3", 669 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 670 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 671 + "license": "MIT", 672 + "dependencies": { 673 + "emoji-regex": "^8.0.0", 674 + "is-fullwidth-code-point": "^3.0.0", 675 + "strip-ansi": "^6.0.1" 676 + }, 677 + "engines": { 678 + "node": ">=8" 679 + } 680 + }, 681 + "node_modules/cliui/node_modules/strip-ansi": { 682 + "version": "6.0.1", 683 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 684 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 685 + "license": "MIT", 686 + "dependencies": { 687 + "ansi-regex": "^5.0.1" 688 + }, 689 + "engines": { 690 + "node": ">=8" 691 + } 692 + }, 693 + "node_modules/cliui/node_modules/wrap-ansi": { 694 + "version": "7.0.0", 695 + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 696 + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 697 + "license": "MIT", 698 + "dependencies": { 699 + "ansi-styles": "^4.0.0", 700 + "string-width": "^4.1.0", 701 + "strip-ansi": "^6.0.0" 702 + }, 703 + "engines": { 704 + "node": ">=10" 705 + }, 706 + "funding": { 707 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 708 + } 709 + }, 710 + "node_modules/color-convert": { 711 + "version": "2.0.1", 712 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 713 + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 714 + "license": "MIT", 715 + "dependencies": { 716 + "color-name": "~1.1.4" 717 + }, 718 + "engines": { 719 + "node": ">=7.0.0" 720 + } 721 + }, 722 + "node_modules/color-name": { 723 + "version": "1.1.4", 724 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 725 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 726 + "license": "MIT" 727 + }, 728 + "node_modules/compressible": { 729 + "version": "2.0.18", 730 + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", 731 + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", 732 + "dev": true, 733 + "license": "MIT", 734 + "dependencies": { 735 + "mime-db": ">= 1.43.0 < 2" 736 + }, 737 + "engines": { 738 + "node": ">= 0.6" 739 + } 740 + }, 741 + "node_modules/compression": { 742 + "version": "1.8.1", 743 + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", 744 + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", 745 + "dev": true, 746 + "license": "MIT", 747 + "dependencies": { 748 + "bytes": "3.1.2", 749 + "compressible": "~2.0.18", 750 + "debug": "2.6.9", 751 + "negotiator": "~0.6.4", 752 + "on-headers": "~1.1.0", 753 + "safe-buffer": "5.2.1", 754 + "vary": "~1.1.2" 755 + }, 756 + "engines": { 757 + "node": ">= 0.8.0" 758 + } 759 + }, 760 + "node_modules/concat-map": { 761 + "version": "0.0.1", 762 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 763 + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 764 + "dev": true, 765 + "license": "MIT" 766 + }, 767 + "node_modules/concurrently": { 768 + "version": "8.2.2", 769 + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", 770 + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", 771 + "dev": true, 772 + "license": "MIT", 773 + "dependencies": { 774 + "chalk": "^4.1.2", 775 + "date-fns": "^2.30.0", 776 + "lodash": "^4.17.21", 777 + "rxjs": "^7.8.1", 778 + "shell-quote": "^1.8.1", 779 + "spawn-command": "0.0.2", 780 + "supports-color": "^8.1.1", 781 + "tree-kill": "^1.2.2", 782 + "yargs": "^17.7.2" 783 + }, 784 + "bin": { 785 + "conc": "dist/bin/concurrently.js", 786 + "concurrently": "dist/bin/concurrently.js" 787 + }, 788 + "engines": { 789 + "node": "^14.13.0 || >=16.0.0" 790 + }, 791 + "funding": { 792 + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" 793 + } 794 + }, 795 + "node_modules/content-disposition": { 796 + "version": "0.5.2", 797 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 798 + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", 799 + "dev": true, 800 + "license": "MIT", 801 + "engines": { 802 + "node": ">= 0.6" 803 + } 804 + }, 805 + "node_modules/cross-spawn": { 806 + "version": "7.0.6", 807 + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 808 + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 809 + "dev": true, 810 + "license": "MIT", 811 + "dependencies": { 812 + "path-key": "^3.1.0", 813 + "shebang-command": "^2.0.0", 814 + "which": "^2.0.1" 815 + }, 816 + "engines": { 817 + "node": ">= 8" 818 + } 819 + }, 820 + "node_modules/crypto-random-string": { 821 + "version": "4.0.0", 822 + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", 823 + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", 824 + "license": "MIT", 825 + "dependencies": { 826 + "type-fest": "^1.0.1" 827 + }, 828 + "engines": { 829 + "node": ">=12" 830 + }, 831 + "funding": { 832 + "url": "https://github.com/sponsors/sindresorhus" 833 + } 834 + }, 835 + "node_modules/crypto-random-string/node_modules/type-fest": { 836 + "version": "1.4.0", 837 + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", 838 + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", 839 + "license": "(MIT OR CC0-1.0)", 840 + "engines": { 841 + "node": ">=10" 842 + }, 843 + "funding": { 844 + "url": "https://github.com/sponsors/sindresorhus" 845 + } 846 + }, 847 + "node_modules/date-fns": { 848 + "version": "2.30.0", 849 + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", 850 + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", 851 + "dev": true, 852 + "license": "MIT", 853 + "dependencies": { 854 + "@babel/runtime": "^7.21.0" 855 + }, 856 + "engines": { 857 + "node": ">=0.11" 858 + }, 859 + "funding": { 860 + "type": "opencollective", 861 + "url": "https://opencollective.com/date-fns" 862 + } 863 + }, 864 + "node_modules/debug": { 865 + "version": "2.6.9", 866 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 867 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 868 + "dev": true, 869 + "license": "MIT", 870 + "dependencies": { 871 + "ms": "2.0.0" 872 + } 873 + }, 874 + "node_modules/deep-extend": { 875 + "version": "0.6.0", 876 + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 877 + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 878 + "dev": true, 879 + "license": "MIT", 880 + "engines": { 881 + "node": ">=4.0.0" 882 + } 883 + }, 884 + "node_modules/eastasianwidth": { 885 + "version": "0.2.0", 886 + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 887 + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 888 + "dev": true, 889 + "license": "MIT" 890 + }, 891 + "node_modules/emoji-regex": { 892 + "version": "9.2.2", 893 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 894 + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 895 + "dev": true, 896 + "license": "MIT" 897 + }, 898 + "node_modules/entities": { 899 + "version": "6.0.1", 900 + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", 901 + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", 902 + "license": "BSD-2-Clause", 903 + "engines": { 904 + "node": ">=0.12" 905 + }, 906 + "funding": { 907 + "url": "https://github.com/fb55/entities?sponsor=1" 908 + } 909 + }, 910 + "node_modules/escalade": { 911 + "version": "3.2.0", 912 + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 913 + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 914 + "license": "MIT", 915 + "engines": { 916 + "node": ">=6" 917 + } 918 + }, 919 + "node_modules/execa": { 920 + "version": "5.1.1", 921 + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", 922 + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", 923 + "dev": true, 924 + "license": "MIT", 925 + "dependencies": { 926 + "cross-spawn": "^7.0.3", 927 + "get-stream": "^6.0.0", 928 + "human-signals": "^2.1.0", 929 + "is-stream": "^2.0.0", 930 + "merge-stream": "^2.0.0", 931 + "npm-run-path": "^4.0.1", 932 + "onetime": "^5.1.2", 933 + "signal-exit": "^3.0.3", 934 + "strip-final-newline": "^2.0.0" 935 + }, 936 + "engines": { 937 + "node": ">=10" 938 + }, 939 + "funding": { 940 + "url": "https://github.com/sindresorhus/execa?sponsor=1" 941 + } 942 + }, 943 + "node_modules/fast-deep-equal": { 944 + "version": "3.1.3", 945 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 946 + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 947 + "dev": true, 948 + "license": "MIT" 949 + }, 950 + "node_modules/fast-xml-parser": { 951 + "version": "4.5.3", 952 + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", 953 + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", 954 + "funding": [ 955 + { 956 + "type": "github", 957 + "url": "https://github.com/sponsors/NaturalIntelligence" 958 + } 959 + ], 960 + "license": "MIT", 961 + "dependencies": { 962 + "strnum": "^1.1.1" 963 + }, 964 + "bin": { 965 + "fxparser": "src/cli/cli.js" 966 + } 967 + }, 968 + "node_modules/get-caller-file": { 969 + "version": "2.0.5", 970 + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 971 + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 972 + "license": "ISC", 973 + "engines": { 974 + "node": "6.* || 8.* || >= 10.*" 975 + } 976 + }, 977 + "node_modules/get-stream": { 978 + "version": "6.0.1", 979 + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", 980 + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", 981 + "dev": true, 982 + "license": "MIT", 983 + "engines": { 984 + "node": ">=10" 985 + }, 986 + "funding": { 987 + "url": "https://github.com/sponsors/sindresorhus" 988 + } 989 + }, 990 + "node_modules/has-flag": { 991 + "version": "4.0.0", 992 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 993 + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 994 + "dev": true, 995 + "license": "MIT", 996 + "engines": { 997 + "node": ">=8" 998 + } 999 + }, 1000 + "node_modules/hash-wasm": { 1001 + "version": "4.12.0", 1002 + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", 1003 + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", 1004 + "license": "MIT" 1005 + }, 1006 + "node_modules/http-status-codes": { 1007 + "version": "2.3.0", 1008 + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", 1009 + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", 1010 + "license": "MIT" 1011 + }, 1012 + "node_modules/human-signals": { 1013 + "version": "2.1.0", 1014 + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", 1015 + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", 1016 + "dev": true, 1017 + "license": "Apache-2.0", 1018 + "engines": { 1019 + "node": ">=10.17.0" 1020 + } 1021 + }, 1022 + "node_modules/idb": { 1023 + "version": "7.1.1", 1024 + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", 1025 + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", 1026 + "license": "ISC" 1027 + }, 1028 + "node_modules/ieee754": { 1029 + "version": "1.2.1", 1030 + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1031 + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 1032 + "funding": [ 1033 + { 1034 + "type": "github", 1035 + "url": "https://github.com/sponsors/feross" 1036 + }, 1037 + { 1038 + "type": "patreon", 1039 + "url": "https://www.patreon.com/feross" 1040 + }, 1041 + { 1042 + "type": "consulting", 1043 + "url": "https://feross.org/support" 1044 + } 1045 + ], 1046 + "license": "BSD-3-Clause" 1047 + }, 1048 + "node_modules/inherits": { 1049 + "version": "2.0.4", 1050 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1051 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1052 + "license": "ISC" 1053 + }, 1054 + "node_modules/ini": { 1055 + "version": "1.3.8", 1056 + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1057 + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 1058 + "dev": true, 1059 + "license": "ISC" 1060 + }, 1061 + "node_modules/is-docker": { 1062 + "version": "2.2.1", 1063 + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", 1064 + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", 1065 + "dev": true, 1066 + "license": "MIT", 1067 + "bin": { 1068 + "is-docker": "cli.js" 1069 + }, 1070 + "engines": { 1071 + "node": ">=8" 1072 + }, 1073 + "funding": { 1074 + "url": "https://github.com/sponsors/sindresorhus" 1075 + } 1076 + }, 1077 + "node_modules/is-fullwidth-code-point": { 1078 + "version": "3.0.0", 1079 + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1080 + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1081 + "license": "MIT", 1082 + "engines": { 1083 + "node": ">=8" 1084 + } 1085 + }, 1086 + "node_modules/is-port-reachable": { 1087 + "version": "4.0.0", 1088 + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", 1089 + "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", 1090 + "dev": true, 1091 + "license": "MIT", 1092 + "engines": { 1093 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1094 + }, 1095 + "funding": { 1096 + "url": "https://github.com/sponsors/sindresorhus" 1097 + } 1098 + }, 1099 + "node_modules/is-stream": { 1100 + "version": "2.0.1", 1101 + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", 1102 + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", 1103 + "dev": true, 1104 + "license": "MIT", 1105 + "engines": { 1106 + "node": ">=8" 1107 + }, 1108 + "funding": { 1109 + "url": "https://github.com/sponsors/sindresorhus" 1110 + } 1111 + }, 1112 + "node_modules/is-wsl": { 1113 + "version": "2.2.0", 1114 + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", 1115 + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", 1116 + "dev": true, 1117 + "license": "MIT", 1118 + "dependencies": { 1119 + "is-docker": "^2.0.0" 1120 + }, 1121 + "engines": { 1122 + "node": ">=8" 1123 + } 1124 + }, 1125 + "node_modules/isexe": { 1126 + "version": "2.0.0", 1127 + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1128 + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1129 + "dev": true, 1130 + "license": "ISC" 1131 + }, 1132 + "node_modules/js-levenshtein": { 1133 + "version": "1.1.6", 1134 + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", 1135 + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", 1136 + "license": "MIT", 1137 + "engines": { 1138 + "node": ">=0.10.0" 1139 + } 1140 + }, 1141 + "node_modules/js-yaml": { 1142 + "version": "4.1.1", 1143 + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", 1144 + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", 1145 + "license": "MIT", 1146 + "dependencies": { 1147 + "argparse": "^2.0.1" 1148 + }, 1149 + "bin": { 1150 + "js-yaml": "bin/js-yaml.js" 1151 + } 1152 + }, 1153 + "node_modules/json-schema-traverse": { 1154 + "version": "1.0.0", 1155 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 1156 + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 1157 + "dev": true, 1158 + "license": "MIT" 1159 + }, 1160 + "node_modules/lodash": { 1161 + "version": "4.17.21", 1162 + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1163 + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1164 + "dev": true, 1165 + "license": "MIT" 1166 + }, 1167 + "node_modules/merge-stream": { 1168 + "version": "2.0.0", 1169 + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 1170 + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", 1171 + "dev": true, 1172 + "license": "MIT" 1173 + }, 1174 + "node_modules/mime": { 1175 + "version": "4.1.0", 1176 + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", 1177 + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", 1178 + "funding": [ 1179 + "https://github.com/sponsors/broofa" 1180 + ], 1181 + "license": "MIT", 1182 + "bin": { 1183 + "mime": "bin/cli.js" 1184 + }, 1185 + "engines": { 1186 + "node": ">=16" 1187 + } 1188 + }, 1189 + "node_modules/mime-db": { 1190 + "version": "1.54.0", 1191 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", 1192 + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", 1193 + "dev": true, 1194 + "license": "MIT", 1195 + "engines": { 1196 + "node": ">= 0.6" 1197 + } 1198 + }, 1199 + "node_modules/mime-types": { 1200 + "version": "2.1.18", 1201 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 1202 + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 1203 + "dev": true, 1204 + "license": "MIT", 1205 + "dependencies": { 1206 + "mime-db": "~1.33.0" 1207 + }, 1208 + "engines": { 1209 + "node": ">= 0.6" 1210 + } 1211 + }, 1212 + "node_modules/mime-types/node_modules/mime-db": { 1213 + "version": "1.33.0", 1214 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 1215 + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", 1216 + "dev": true, 1217 + "license": "MIT", 1218 + "engines": { 1219 + "node": ">= 0.6" 1220 + } 1221 + }, 1222 + "node_modules/mimic-fn": { 1223 + "version": "2.1.0", 1224 + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 1225 + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 1226 + "dev": true, 1227 + "license": "MIT", 1228 + "engines": { 1229 + "node": ">=6" 1230 + } 1231 + }, 1232 + "node_modules/minimatch": { 1233 + "version": "3.1.2", 1234 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1235 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1236 + "dev": true, 1237 + "license": "ISC", 1238 + "dependencies": { 1239 + "brace-expansion": "^1.1.7" 1240 + }, 1241 + "engines": { 1242 + "node": "*" 1243 + } 1244 + }, 1245 + "node_modules/minimist": { 1246 + "version": "1.2.8", 1247 + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1248 + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1249 + "dev": true, 1250 + "license": "MIT", 1251 + "funding": { 1252 + "url": "https://github.com/sponsors/ljharb" 1253 + } 1254 + }, 1255 + "node_modules/ms": { 1256 + "version": "2.0.0", 1257 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1258 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 1259 + "dev": true, 1260 + "license": "MIT" 1261 + }, 1262 + "node_modules/negotiator": { 1263 + "version": "0.6.4", 1264 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", 1265 + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", 1266 + "dev": true, 1267 + "license": "MIT", 1268 + "engines": { 1269 + "node": ">= 0.6" 1270 + } 1271 + }, 1272 + "node_modules/npm-run-path": { 1273 + "version": "4.0.1", 1274 + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", 1275 + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 1276 + "dev": true, 1277 + "license": "MIT", 1278 + "dependencies": { 1279 + "path-key": "^3.0.0" 1280 + }, 1281 + "engines": { 1282 + "node": ">=8" 1283 + } 1284 + }, 1285 + "node_modules/on-headers": { 1286 + "version": "1.1.0", 1287 + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", 1288 + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", 1289 + "dev": true, 1290 + "license": "MIT", 1291 + "engines": { 1292 + "node": ">= 0.8" 1293 + } 1294 + }, 1295 + "node_modules/onetime": { 1296 + "version": "5.1.2", 1297 + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 1298 + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 1299 + "dev": true, 1300 + "license": "MIT", 1301 + "dependencies": { 1302 + "mimic-fn": "^2.1.0" 1303 + }, 1304 + "engines": { 1305 + "node": ">=6" 1306 + }, 1307 + "funding": { 1308 + "url": "https://github.com/sponsors/sindresorhus" 1309 + } 1310 + }, 1311 + "node_modules/pako": { 1312 + "version": "1.0.11", 1313 + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 1314 + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 1315 + "license": "(MIT AND Zlib)" 1316 + }, 1317 + "node_modules/parse5": { 1318 + "version": "7.3.0", 1319 + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", 1320 + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", 1321 + "license": "MIT", 1322 + "dependencies": { 1323 + "entities": "^6.0.0" 1324 + }, 1325 + "funding": { 1326 + "url": "https://github.com/inikulin/parse5?sponsor=1" 1327 + } 1328 + }, 1329 + "node_modules/parse5-html-rewriting-stream": { 1330 + "version": "7.1.0", 1331 + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.1.0.tgz", 1332 + "integrity": "sha512-2ifK6Jb+ONoqOy5f+cYHsqvx1obHQdvIk13Jmt/5ezxP0U9p+fqd+R6O73KblGswyuzBYfetmsfK9ThMgnuPPg==", 1333 + "license": "MIT", 1334 + "dependencies": { 1335 + "entities": "^6.0.0", 1336 + "parse5": "^7.0.0", 1337 + "parse5-sax-parser": "^7.0.0" 1338 + }, 1339 + "funding": { 1340 + "url": "https://github.com/inikulin/parse5?sponsor=1" 1341 + } 1342 + }, 1343 + "node_modules/parse5-sax-parser": { 1344 + "version": "7.0.0", 1345 + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", 1346 + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", 1347 + "license": "MIT", 1348 + "dependencies": { 1349 + "parse5": "^7.0.0" 1350 + }, 1351 + "funding": { 1352 + "url": "https://github.com/inikulin/parse5?sponsor=1" 1353 + } 1354 + }, 1355 + "node_modules/path-is-inside": { 1356 + "version": "1.0.2", 1357 + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1358 + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", 1359 + "dev": true, 1360 + "license": "(WTFPL OR MIT)" 1361 + }, 1362 + "node_modules/path-key": { 1363 + "version": "3.1.1", 1364 + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1365 + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1366 + "dev": true, 1367 + "license": "MIT", 1368 + "engines": { 1369 + "node": ">=8" 1370 + } 1371 + }, 1372 + "node_modules/path-parser": { 1373 + "version": "6.1.0", 1374 + "resolved": "https://registry.npmjs.org/path-parser/-/path-parser-6.1.0.tgz", 1375 + "integrity": "sha512-nAB6J73z2rFcQP+870OHhpkHFj5kO4rPLc2Ol4Y3Ale7F6Hk1/cPKp7cQ8RznKF8FOSvu+YR9Xc6Gafk7DlpYA==", 1376 + "license": "MIT", 1377 + "dependencies": { 1378 + "search-params": "3.0.0", 1379 + "tslib": "^1.10.0" 1380 + } 1381 + }, 1382 + "node_modules/path-parser/node_modules/tslib": { 1383 + "version": "1.14.1", 1384 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1385 + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1386 + "license": "0BSD" 1387 + }, 1388 + "node_modules/path-to-regexp": { 1389 + "version": "3.3.0", 1390 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", 1391 + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", 1392 + "dev": true, 1393 + "license": "MIT" 1394 + }, 1395 + "node_modules/process": { 1396 + "version": "0.11.10", 1397 + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 1398 + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 1399 + "license": "MIT", 1400 + "engines": { 1401 + "node": ">= 0.6.0" 1402 + } 1403 + }, 1404 + "node_modules/punycode": { 1405 + "version": "2.3.1", 1406 + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1407 + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 1408 + "dev": true, 1409 + "license": "MIT", 1410 + "engines": { 1411 + "node": ">=6" 1412 + } 1413 + }, 1414 + "node_modules/pvtsutils": { 1415 + "version": "1.3.6", 1416 + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", 1417 + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", 1418 + "license": "MIT", 1419 + "dependencies": { 1420 + "tslib": "^2.8.1" 1421 + } 1422 + }, 1423 + "node_modules/pvutils": { 1424 + "version": "1.1.5", 1425 + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", 1426 + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", 1427 + "license": "MIT", 1428 + "engines": { 1429 + "node": ">=16.0.0" 1430 + } 1431 + }, 1432 + "node_modules/range-parser": { 1433 + "version": "1.2.0", 1434 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 1435 + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", 1436 + "dev": true, 1437 + "license": "MIT", 1438 + "engines": { 1439 + "node": ">= 0.6" 1440 + } 1441 + }, 1442 + "node_modules/rc": { 1443 + "version": "1.2.8", 1444 + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 1445 + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 1446 + "dev": true, 1447 + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", 1448 + "dependencies": { 1449 + "deep-extend": "^0.6.0", 1450 + "ini": "~1.3.0", 1451 + "minimist": "^1.2.0", 1452 + "strip-json-comments": "~2.0.1" 1453 + }, 1454 + "bin": { 1455 + "rc": "cli.js" 1456 + } 1457 + }, 1458 + "node_modules/readable-stream": { 1459 + "version": "3.6.2", 1460 + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 1461 + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 1462 + "license": "MIT", 1463 + "dependencies": { 1464 + "inherits": "^2.0.3", 1465 + "string_decoder": "^1.1.1", 1466 + "util-deprecate": "^1.0.1" 1467 + }, 1468 + "engines": { 1469 + "node": ">= 6" 1470 + } 1471 + }, 1472 + "node_modules/reflect-metadata": { 1473 + "version": "0.2.2", 1474 + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", 1475 + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", 1476 + "license": "Apache-2.0" 1477 + }, 1478 + "node_modules/registry-auth-token": { 1479 + "version": "3.3.2", 1480 + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", 1481 + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", 1482 + "dev": true, 1483 + "license": "MIT", 1484 + "dependencies": { 1485 + "rc": "^1.1.6", 1486 + "safe-buffer": "^5.0.1" 1487 + } 1488 + }, 1489 + "node_modules/registry-url": { 1490 + "version": "3.1.0", 1491 + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", 1492 + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", 1493 + "dev": true, 1494 + "license": "MIT", 1495 + "dependencies": { 1496 + "rc": "^1.0.1" 1497 + }, 1498 + "engines": { 1499 + "node": ">=0.10.0" 1500 + } 1501 + }, 1502 + "node_modules/require-directory": { 1503 + "version": "2.1.1", 1504 + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1505 + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1506 + "license": "MIT", 1507 + "engines": { 1508 + "node": ">=0.10.0" 1509 + } 1510 + }, 1511 + "node_modules/require-from-string": { 1512 + "version": "2.0.2", 1513 + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 1514 + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 1515 + "dev": true, 1516 + "license": "MIT", 1517 + "engines": { 1518 + "node": ">=0.10.0" 1519 + } 1520 + }, 1521 + "node_modules/rxjs": { 1522 + "version": "7.8.2", 1523 + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", 1524 + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", 1525 + "dev": true, 1526 + "license": "Apache-2.0", 1527 + "dependencies": { 1528 + "tslib": "^2.1.0" 1529 + } 1530 + }, 1531 + "node_modules/safe-buffer": { 1532 + "version": "5.2.1", 1533 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1534 + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1535 + "funding": [ 1536 + { 1537 + "type": "github", 1538 + "url": "https://github.com/sponsors/feross" 1539 + }, 1540 + { 1541 + "type": "patreon", 1542 + "url": "https://www.patreon.com/feross" 1543 + }, 1544 + { 1545 + "type": "consulting", 1546 + "url": "https://feross.org/support" 1547 + } 1548 + ], 1549 + "license": "MIT" 1550 + }, 1551 + "node_modules/search-params": { 1552 + "version": "3.0.0", 1553 + "resolved": "https://registry.npmjs.org/search-params/-/search-params-3.0.0.tgz", 1554 + "integrity": "sha512-8CYNl/bjkEhXWbDTU/K7c2jQtrnqEffIPyOLMqygW/7/b+ym8UtQumcAZjOfMLjZKR6AxK5tOr9fChbQZCzPqg==", 1555 + "license": "MIT" 1556 + }, 1557 + "node_modules/serve": { 1558 + "version": "14.2.5", 1559 + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.5.tgz", 1560 + "integrity": "sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==", 1561 + "dev": true, 1562 + "license": "MIT", 1563 + "dependencies": { 1564 + "@zeit/schemas": "2.36.0", 1565 + "ajv": "8.12.0", 1566 + "arg": "5.0.2", 1567 + "boxen": "7.0.0", 1568 + "chalk": "5.0.1", 1569 + "chalk-template": "0.4.0", 1570 + "clipboardy": "3.0.0", 1571 + "compression": "1.8.1", 1572 + "is-port-reachable": "4.0.0", 1573 + "serve-handler": "6.1.6", 1574 + "update-check": "1.5.4" 1575 + }, 1576 + "bin": { 1577 + "serve": "build/main.js" 1578 + }, 1579 + "engines": { 1580 + "node": ">= 14" 1581 + } 1582 + }, 1583 + "node_modules/serve-handler": { 1584 + "version": "6.1.6", 1585 + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", 1586 + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", 1587 + "dev": true, 1588 + "license": "MIT", 1589 + "dependencies": { 1590 + "bytes": "3.0.0", 1591 + "content-disposition": "0.5.2", 1592 + "mime-types": "2.1.18", 1593 + "minimatch": "3.1.2", 1594 + "path-is-inside": "1.0.2", 1595 + "path-to-regexp": "3.3.0", 1596 + "range-parser": "1.2.0" 1597 + } 1598 + }, 1599 + "node_modules/serve-handler/node_modules/bytes": { 1600 + "version": "3.0.0", 1601 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 1602 + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", 1603 + "dev": true, 1604 + "license": "MIT", 1605 + "engines": { 1606 + "node": ">= 0.8" 1607 + } 1608 + }, 1609 + "node_modules/serve/node_modules/chalk": { 1610 + "version": "5.0.1", 1611 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", 1612 + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", 1613 + "dev": true, 1614 + "license": "MIT", 1615 + "engines": { 1616 + "node": "^12.17.0 || ^14.13 || >=16.0.0" 1617 + }, 1618 + "funding": { 1619 + "url": "https://github.com/chalk/chalk?sponsor=1" 1620 + } 1621 + }, 1622 + "node_modules/shebang-command": { 1623 + "version": "2.0.0", 1624 + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1625 + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1626 + "dev": true, 1627 + "license": "MIT", 1628 + "dependencies": { 1629 + "shebang-regex": "^3.0.0" 1630 + }, 1631 + "engines": { 1632 + "node": ">=8" 1633 + } 1634 + }, 1635 + "node_modules/shebang-regex": { 1636 + "version": "3.0.0", 1637 + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1638 + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1639 + "dev": true, 1640 + "license": "MIT", 1641 + "engines": { 1642 + "node": ">=8" 1643 + } 1644 + }, 1645 + "node_modules/shell-quote": { 1646 + "version": "1.8.3", 1647 + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", 1648 + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", 1649 + "dev": true, 1650 + "license": "MIT", 1651 + "engines": { 1652 + "node": ">= 0.4" 1653 + }, 1654 + "funding": { 1655 + "url": "https://github.com/sponsors/ljharb" 1656 + } 1657 + }, 1658 + "node_modules/signal-exit": { 1659 + "version": "3.0.7", 1660 + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", 1661 + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", 1662 + "dev": true, 1663 + "license": "ISC" 1664 + }, 1665 + "node_modules/spawn-command": { 1666 + "version": "0.0.2", 1667 + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", 1668 + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", 1669 + "dev": true 1670 + }, 1671 + "node_modules/stream-browserify": { 1672 + "version": "3.0.0", 1673 + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", 1674 + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", 1675 + "license": "MIT", 1676 + "dependencies": { 1677 + "inherits": "~2.0.4", 1678 + "readable-stream": "^3.5.0" 1679 + } 1680 + }, 1681 + "node_modules/string_decoder": { 1682 + "version": "1.3.0", 1683 + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1684 + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1685 + "license": "MIT", 1686 + "dependencies": { 1687 + "safe-buffer": "~5.2.0" 1688 + } 1689 + }, 1690 + "node_modules/string-width": { 1691 + "version": "5.1.2", 1692 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 1693 + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 1694 + "dev": true, 1695 + "license": "MIT", 1696 + "dependencies": { 1697 + "eastasianwidth": "^0.2.0", 1698 + "emoji-regex": "^9.2.2", 1699 + "strip-ansi": "^7.0.1" 1700 + }, 1701 + "engines": { 1702 + "node": ">=12" 1703 + }, 1704 + "funding": { 1705 + "url": "https://github.com/sponsors/sindresorhus" 1706 + } 1707 + }, 1708 + "node_modules/strip-ansi": { 1709 + "version": "7.1.2", 1710 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", 1711 + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", 1712 + "dev": true, 1713 + "license": "MIT", 1714 + "dependencies": { 1715 + "ansi-regex": "^6.0.1" 1716 + }, 1717 + "engines": { 1718 + "node": ">=12" 1719 + }, 1720 + "funding": { 1721 + "url": "https://github.com/chalk/strip-ansi?sponsor=1" 1722 + } 1723 + }, 1724 + "node_modules/strip-final-newline": { 1725 + "version": "2.0.0", 1726 + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 1727 + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", 1728 + "dev": true, 1729 + "license": "MIT", 1730 + "engines": { 1731 + "node": ">=6" 1732 + } 1733 + }, 1734 + "node_modules/strip-json-comments": { 1735 + "version": "2.0.1", 1736 + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1737 + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 1738 + "dev": true, 1739 + "license": "MIT", 1740 + "engines": { 1741 + "node": ">=0.10.0" 1742 + } 1743 + }, 1744 + "node_modules/strnum": { 1745 + "version": "1.1.2", 1746 + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", 1747 + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", 1748 + "funding": [ 1749 + { 1750 + "type": "github", 1751 + "url": "https://github.com/sponsors/NaturalIntelligence" 1752 + } 1753 + ], 1754 + "license": "MIT" 1755 + }, 1756 + "node_modules/supports-color": { 1757 + "version": "8.1.1", 1758 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1759 + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1760 + "dev": true, 1761 + "license": "MIT", 1762 + "dependencies": { 1763 + "has-flag": "^4.0.0" 1764 + }, 1765 + "engines": { 1766 + "node": ">=10" 1767 + }, 1768 + "funding": { 1769 + "url": "https://github.com/chalk/supports-color?sponsor=1" 1770 + } 1771 + }, 1772 + "node_modules/temp-dir": { 1773 + "version": "3.0.0", 1774 + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", 1775 + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", 1776 + "license": "MIT", 1777 + "engines": { 1778 + "node": ">=14.16" 1779 + } 1780 + }, 1781 + "node_modules/tempy": { 1782 + "version": "3.1.0", 1783 + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", 1784 + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", 1785 + "license": "MIT", 1786 + "dependencies": { 1787 + "is-stream": "^3.0.0", 1788 + "temp-dir": "^3.0.0", 1789 + "type-fest": "^2.12.2", 1790 + "unique-string": "^3.0.0" 1791 + }, 1792 + "engines": { 1793 + "node": ">=14.16" 1794 + }, 1795 + "funding": { 1796 + "url": "https://github.com/sponsors/sindresorhus" 1797 + } 1798 + }, 1799 + "node_modules/tempy/node_modules/is-stream": { 1800 + "version": "3.0.0", 1801 + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", 1802 + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", 1803 + "license": "MIT", 1804 + "engines": { 1805 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1806 + }, 1807 + "funding": { 1808 + "url": "https://github.com/sponsors/sindresorhus" 1809 + } 1810 + }, 1811 + "node_modules/to-data-view": { 1812 + "version": "2.0.0", 1813 + "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-2.0.0.tgz", 1814 + "integrity": "sha512-RGEM5KqlPHr+WVTPmGNAXNeFEmsBnlkxXaIfEpUYV0AST2Z5W1EGq9L/MENFrMMmL2WQr1wjkmZy/M92eKhjYA==", 1815 + "license": "MIT", 1816 + "engines": { 1817 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1818 + } 1819 + }, 1820 + "node_modules/tree-kill": { 1821 + "version": "1.2.2", 1822 + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 1823 + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", 1824 + "dev": true, 1825 + "license": "MIT", 1826 + "bin": { 1827 + "tree-kill": "cli.js" 1828 + } 1829 + }, 1830 + "node_modules/tslib": { 1831 + "version": "2.8.1", 1832 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1833 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1834 + "license": "0BSD" 1835 + }, 1836 + "node_modules/tsyringe": { 1837 + "version": "4.10.0", 1838 + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", 1839 + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", 1840 + "license": "MIT", 1841 + "dependencies": { 1842 + "tslib": "^1.9.3" 1843 + }, 1844 + "engines": { 1845 + "node": ">= 6.0.0" 1846 + } 1847 + }, 1848 + "node_modules/tsyringe/node_modules/tslib": { 1849 + "version": "1.14.1", 1850 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1851 + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1852 + "license": "0BSD" 1853 + }, 1854 + "node_modules/type-fest": { 1855 + "version": "2.19.0", 1856 + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", 1857 + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", 1858 + "license": "(MIT OR CC0-1.0)", 1859 + "engines": { 1860 + "node": ">=12.20" 1861 + }, 1862 + "funding": { 1863 + "url": "https://github.com/sponsors/sindresorhus" 1864 + } 1865 + }, 1866 + "node_modules/undici-types": { 1867 + "version": "7.16.0", 1868 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", 1869 + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", 1870 + "license": "MIT" 1871 + }, 1872 + "node_modules/unique-string": { 1873 + "version": "3.0.0", 1874 + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", 1875 + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", 1876 + "license": "MIT", 1877 + "dependencies": { 1878 + "crypto-random-string": "^4.0.0" 1879 + }, 1880 + "engines": { 1881 + "node": ">=12" 1882 + }, 1883 + "funding": { 1884 + "url": "https://github.com/sponsors/sindresorhus" 1885 + } 1886 + }, 1887 + "node_modules/update-check": { 1888 + "version": "1.5.4", 1889 + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", 1890 + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", 1891 + "dev": true, 1892 + "license": "MIT", 1893 + "dependencies": { 1894 + "registry-auth-token": "3.3.2", 1895 + "registry-url": "3.1.0" 1896 + } 1897 + }, 1898 + "node_modules/uri-js": { 1899 + "version": "4.4.1", 1900 + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1901 + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1902 + "dev": true, 1903 + "license": "BSD-2-Clause", 1904 + "dependencies": { 1905 + "punycode": "^2.1.0" 1906 + } 1907 + }, 1908 + "node_modules/util-deprecate": { 1909 + "version": "1.0.2", 1910 + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1911 + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1912 + "license": "MIT" 1913 + }, 1914 + "node_modules/uuid-random": { 1915 + "version": "1.3.2", 1916 + "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", 1917 + "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==", 1918 + "license": "MIT" 1919 + }, 1920 + "node_modules/vary": { 1921 + "version": "1.1.2", 1922 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1923 + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 1924 + "dev": true, 1925 + "license": "MIT", 1926 + "engines": { 1927 + "node": ">= 0.8" 1928 + } 1929 + }, 1930 + "node_modules/warcio": { 1931 + "version": "2.4.7", 1932 + "resolved": "https://registry.npmjs.org/warcio/-/warcio-2.4.7.tgz", 1933 + "integrity": "sha512-WGRqvoUqSalAkx+uJ8xnrxiiSPZ7Ru/h7iKC2XmuMMSOUSnS917l4V+qpaN9thAsZkZ+8qJRtee3uyOjlq4Dgg==", 1934 + "license": "Apache-2.0", 1935 + "dependencies": { 1936 + "@types/pako": "^1.0.7", 1937 + "@types/stream-buffers": "^3.0.7", 1938 + "base32-encode": "^2.0.0", 1939 + "hash-wasm": "^4.9.0", 1940 + "pako": "^1.0.11", 1941 + "tempy": "^3.1.0", 1942 + "uuid-random": "^1.3.2", 1943 + "yargs": "^17.7.2" 1944 + }, 1945 + "bin": { 1946 + "warcio": "dist/cli.js" 1947 + }, 1948 + "engines": { 1949 + "node": ">=18.0.0" 1950 + } 1951 + }, 1952 + "node_modules/which": { 1953 + "version": "2.0.2", 1954 + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1955 + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1956 + "dev": true, 1957 + "license": "ISC", 1958 + "dependencies": { 1959 + "isexe": "^2.0.0" 1960 + }, 1961 + "bin": { 1962 + "node-which": "bin/node-which" 1963 + }, 1964 + "engines": { 1965 + "node": ">= 8" 1966 + } 1967 + }, 1968 + "node_modules/widest-line": { 1969 + "version": "4.0.1", 1970 + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", 1971 + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", 1972 + "dev": true, 1973 + "license": "MIT", 1974 + "dependencies": { 1975 + "string-width": "^5.0.1" 1976 + }, 1977 + "engines": { 1978 + "node": ">=12" 1979 + }, 1980 + "funding": { 1981 + "url": "https://github.com/sponsors/sindresorhus" 1982 + } 1983 + }, 1984 + "node_modules/wrap-ansi": { 1985 + "version": "8.1.0", 1986 + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 1987 + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 1988 + "dev": true, 1989 + "license": "MIT", 1990 + "dependencies": { 1991 + "ansi-styles": "^6.1.0", 1992 + "string-width": "^5.0.1", 1993 + "strip-ansi": "^7.0.1" 1994 + }, 1995 + "engines": { 1996 + "node": ">=12" 1997 + }, 1998 + "funding": { 1999 + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 2000 + } 2001 + }, 2002 + "node_modules/wrap-ansi/node_modules/ansi-styles": { 2003 + "version": "6.2.3", 2004 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", 2005 + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", 2006 + "dev": true, 2007 + "license": "MIT", 2008 + "engines": { 2009 + "node": ">=12" 2010 + }, 2011 + "funding": { 2012 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 2013 + } 2014 + }, 2015 + "node_modules/y18n": { 2016 + "version": "5.0.8", 2017 + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 2018 + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 2019 + "license": "ISC", 2020 + "engines": { 2021 + "node": ">=10" 2022 + } 2023 + }, 2024 + "node_modules/yargs": { 2025 + "version": "17.7.2", 2026 + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 2027 + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 2028 + "license": "MIT", 2029 + "dependencies": { 2030 + "cliui": "^8.0.1", 2031 + "escalade": "^3.1.1", 2032 + "get-caller-file": "^2.0.5", 2033 + "require-directory": "^2.1.1", 2034 + "string-width": "^4.2.3", 2035 + "y18n": "^5.0.5", 2036 + "yargs-parser": "^21.1.1" 2037 + }, 2038 + "engines": { 2039 + "node": ">=12" 2040 + } 2041 + }, 2042 + "node_modules/yargs-parser": { 2043 + "version": "21.1.1", 2044 + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 2045 + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 2046 + "license": "ISC", 2047 + "engines": { 2048 + "node": ">=12" 2049 + } 2050 + }, 2051 + "node_modules/yargs/node_modules/ansi-regex": { 2052 + "version": "5.0.1", 2053 + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2054 + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2055 + "license": "MIT", 2056 + "engines": { 2057 + "node": ">=8" 2058 + } 2059 + }, 2060 + "node_modules/yargs/node_modules/emoji-regex": { 2061 + "version": "8.0.0", 2062 + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 2063 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 2064 + "license": "MIT" 2065 + }, 2066 + "node_modules/yargs/node_modules/string-width": { 2067 + "version": "4.2.3", 2068 + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2069 + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2070 + "license": "MIT", 2071 + "dependencies": { 2072 + "emoji-regex": "^8.0.0", 2073 + "is-fullwidth-code-point": "^3.0.0", 2074 + "strip-ansi": "^6.0.1" 2075 + }, 2076 + "engines": { 2077 + "node": ">=8" 2078 + } 2079 + }, 2080 + "node_modules/yargs/node_modules/strip-ansi": { 2081 + "version": "6.0.1", 2082 + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2083 + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2084 + "license": "MIT", 2085 + "dependencies": { 2086 + "ansi-regex": "^5.0.1" 2087 + }, 2088 + "engines": { 2089 + "node": ">=8" 2090 + } 2091 + } 2092 + } 2093 + }
+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 + }
+19
sure-client-proxy/src/client-metadata.json
··· 1 + { 2 + "client_id": "http://127.0.0.1:8081/client-metadata.json", 3 + "client_uri": "http://127.0.0.1:8081", 4 + "redirect_uris": [ 5 + "http://127.0.0.1:8081/oauth-callback.html" 6 + ], 7 + "application_type": "web", 8 + "client_name": "Seams (Local Dev)", 9 + "dpop_bound_access_tokens": true, 10 + "grant_types": [ 11 + "authorization_code", 12 + "refresh_token" 13 + ], 14 + "response_types": [ 15 + "code" 16 + ], 17 + "scope": "atproto transition:generic", 18 + "token_endpoint_auth_method": "none" 19 + }
+205
sure-client-proxy/src/index.html
··· 1 + <!DOCTYPE html> 2 + <html> 3 + <head> 4 + <title>Seams Proxy</title> 5 + <meta charset="utf-8"> 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> 108 + <script src="./loadwabac.js"></script> 109 + <!-- Shell script - manages BackgroundWorker and message routing --> 110 + <script type="module" src="./seams-shell.js"></script> 111 + </head> 112 + <body> 113 + <div id="header"> 114 + <input type="text" id="urlInput" placeholder="Enter URL to proxy..." /> 115 + <button onclick="loadUrl()">Go</button> 116 + </div> 117 + <div id="main-container"> 118 + <iframe 119 + id="content" 120 + class="sidebar-open" 121 + sandbox="allow-downloads allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-same-origin allow-forms" 122 + ></iframe> 123 + <!-- Sidebar container - Sidebar component rendered directly by shell.ts --> 124 + <div id="sidebar-container" class="sidebar-container"></div> 125 + <button id="toggle-btn" class="sidebar-open" title="Toggle sidebar">&lt;&lt;</button> 126 + </div> 127 + <script> 128 + // Try with official Webrecorder CORS proxy for testing 129 + // const corsProxy = 'https://wabac-cors-proxy.webrecorder.workers.dev/proxy/'; 130 + // Use our local CORS proxy (127.0.0.1 for RFC 8252 OAuth compatibility) 131 + const corsProxy = 'http://127.0.0.1:8082/proxy/'; 132 + 133 + console.log('[index] Using CORS proxy:', corsProxy); 134 + const proxy = new SeamsLiveProxy({ corsProxy }); 135 + proxy.init(); 136 + 137 + function loadUrl() { 138 + const url = document.getElementById('urlInput').value; 139 + if (url) { 140 + window.location.hash = url; 141 + } 142 + } 143 + 144 + document.getElementById('urlInput').addEventListener('keypress', (e) => { 145 + if (e.key === 'Enter') loadUrl(); 146 + }); 147 + 148 + // Sync URL input with hash 149 + function syncUrlInput() { 150 + const hash = window.location.hash.slice(1); 151 + if (hash) { 152 + document.getElementById('urlInput').value = hash; 153 + } 154 + } 155 + window.addEventListener('hashchange', syncUrlInput); 156 + syncUrlInput(); 157 + 158 + // Sidebar toggle functionality 159 + const sidebarContainer = document.getElementById('sidebar-container'); 160 + const contentFrame = document.getElementById('content'); 161 + const toggleBtn = document.getElementById('toggle-btn'); 162 + let sidebarOpen = true; 163 + 164 + function toggleSidebar() { 165 + sidebarOpen = !sidebarOpen; 166 + if (sidebarOpen) { 167 + sidebarContainer.classList.remove('hidden'); 168 + contentFrame.classList.add('sidebar-open'); 169 + toggleBtn.classList.add('sidebar-open'); 170 + toggleBtn.innerHTML = '&lt;&lt;'; 171 + } else { 172 + sidebarContainer.classList.add('hidden'); 173 + contentFrame.classList.remove('sidebar-open'); 174 + toggleBtn.classList.remove('sidebar-open'); 175 + toggleBtn.innerHTML = '&gt;&gt;'; 176 + } 177 + } 178 + 179 + toggleBtn.addEventListener('click', toggleSidebar); 180 + 181 + // Hook into proxy URL changes to notify shell 182 + // Shell (seams-shell.js) handles all message routing between content and sidebar 183 + const originalOnIframeLoad = proxy.onIframeLoad.bind(proxy); 184 + proxy.onIframeLoad = function(iframeUrl) { 185 + originalOnIframeLoad(iframeUrl); 186 + // Notify shell of URL change 187 + if (this.url && window.SeamsShell) { 188 + console.log('[index] Navigation detected, notifying shell:', this.url); 189 + window.SeamsShell.setUrl(this.url); 190 + } 191 + }; 192 + 193 + const originalOnHashChange = proxy.onHashChange.bind(proxy); 194 + proxy.onHashChange = function() { 195 + originalOnHashChange(); 196 + // Notify shell of URL change 197 + if (this.url && window.SeamsShell) { 198 + console.log('[index] Hash change detected, notifying shell:', this.url); 199 + window.SeamsShell.setUrl(this.url); 200 + } 201 + }; 202 + 203 + </script> 204 + </body> 205 + </html>
+194
sure-client-proxy/src/loadwabac.js
··· 1 + /** 2 + * SeamsLiveProxy - Client-side web proxy using wabac.js service worker 3 + * 4 + * Based on https://github.com/webrecorder/wabac.js/blob/main/examples/live-proxy/loadwabac.js 5 + */ 6 + class SeamsLiveProxy { 7 + constructor({ 8 + corsProxy = 'http://127.0.0.1:8082/proxy/', 9 + collName = 'liveproxy', 10 + injectScripts = '/seams-client.js' 11 + } = {}) { 12 + this.corsProxy = corsProxy; 13 + this.collName = collName; 14 + this.injectScripts = injectScripts; 15 + 16 + this.url = ''; 17 + this.ts = ''; 18 + 19 + // Regex to match collection URL pattern: liveproxy/20231225mp_/https://... 20 + this.matchRx = new RegExp(`${collName}\\/([\\d]+)?\\w\\w_\\/(.*)`); 21 + } 22 + 23 + async init() { 24 + console.log('[loadwabac] Initializing SeamsLiveProxy'); 25 + console.log('[loadwabac] CORS proxy:', this.corsProxy); 26 + 27 + const scope = './'; 28 + 29 + // Register service worker with script injection 30 + const swParams = new URLSearchParams({ 31 + injectScripts: this.injectScripts, 32 + }); 33 + 34 + console.log('[loadwabac] Registering service worker with params:', swParams.toString()); 35 + 36 + // Register the service worker 37 + await navigator.serviceWorker.register( 38 + `./sw.js?${swParams.toString()}`, 39 + { scope } 40 + ); 41 + 42 + console.log('[loadwabac] Service worker registered'); 43 + 44 + // Set up message listener for collAdded BEFORE sending addColl 45 + let initedResolve = null; 46 + const inited = new Promise((resolve) => (initedResolve = resolve)); 47 + 48 + navigator.serviceWorker.addEventListener('message', (event) => { 49 + console.log('[loadwabac] Received message from SW:', event.data); 50 + if (event.data.msg_type === 'collAdded') { 51 + console.log('[loadwabac] Collection added, ready for replay'); 52 + initedResolve(); 53 + } 54 + }); 55 + 56 + // Build base URL (without hash) 57 + const baseUrl = new URL(window.location); 58 + baseUrl.hash = ''; 59 + 60 + // Configure the live proxy collection - matching the reference implementation 61 + const msg = { 62 + msg_type: 'addColl', 63 + name: this.collName, 64 + type: 'live', 65 + file: { sourceUrl: `proxy:${this.corsProxy}` }, 66 + skipExisting: false, 67 + extraConfig: { 68 + prefix: this.corsProxy, 69 + isLive: false, 70 + baseUrl: baseUrl.href, 71 + baseUrlHashReplay: true, 72 + noPostToGet: true, 73 + }, 74 + }; 75 + 76 + console.log('[loadwabac] addColl message:', msg); 77 + 78 + // Send message to service worker controller 79 + if (!navigator.serviceWorker.controller) { 80 + console.log('[loadwabac] No controller yet, waiting for controllerchange'); 81 + await new Promise((resolve) => { 82 + navigator.serviceWorker.addEventListener('controllerchange', () => { 83 + console.log('[loadwabac] Controller changed, now sending addColl message'); 84 + navigator.serviceWorker.controller.postMessage(msg); 85 + resolve(); 86 + }); 87 + }); 88 + } else { 89 + console.log('[loadwabac] Sending addColl message to existing controller'); 90 + navigator.serviceWorker.controller.postMessage(msg); 91 + } 92 + 93 + // Wait for collection to be ready 94 + await inited; 95 + console.log('[loadwabac] Collection ready'); 96 + 97 + // Set up iframe load listener 98 + window.addEventListener('load', () => { 99 + const iframe = document.querySelector('#content'); 100 + if (iframe) { 101 + iframe.addEventListener('load', () => { 102 + try { 103 + const iframeHref = iframe.contentWindow.location.href; 104 + console.log('[loadwabac] Iframe loaded:', iframeHref); 105 + this.onIframeLoad(iframeHref); 106 + } catch (e) { 107 + // Cross-origin access blocked - this means SW didn't intercept 108 + console.warn('[loadwabac] Cannot read iframe location (cross-origin) - SW may not be intercepting'); 109 + } 110 + }); 111 + } 112 + }); 113 + 114 + // Set up hash change listeners 115 + window.addEventListener('hashchange', () => { 116 + this.onHashChange(); 117 + }); 118 + 119 + // Initial load after everything is set up 120 + window.addEventListener('load', () => { 121 + this.onHashChange(); 122 + }); 123 + 124 + // Also trigger immediately if page is already loaded 125 + if (document.readyState === 'complete') { 126 + this.onHashChange(); 127 + } 128 + } 129 + 130 + onHashChange() { 131 + // Parse hash: #https://example.com or #20231225/https://example.com 132 + const hash = window.location.hash.slice(1); 133 + 134 + // Match pattern: optional timestamp followed by URL 135 + const m = hash.match(/\/?(?:([\d]+)\/)?(.*)/); 136 + 137 + const url = m?.[2] || ''; 138 + const ts = m?.[1] || ''; 139 + 140 + // Need a valid URL - default to example.com like reference 141 + const finalUrl = url || 'https://example.com/'; 142 + 143 + // Don't change if same URL 144 + if (finalUrl === this.url && ts === this.ts) { 145 + return; 146 + } 147 + 148 + console.log(`[loadwabac] Loading URL: ${finalUrl}`); 149 + 150 + // Build iframe URL: /w/liveproxy/mp_/https://example.com 151 + const iframeUrl = ts 152 + ? `/w/${this.collName}/${ts}mp_/${finalUrl}` 153 + : `/w/${this.collName}/mp_/${finalUrl}`; 154 + 155 + console.log(`[loadwabac] Setting iframe src to: ${iframeUrl}`); 156 + 157 + const iframe = document.querySelector('#content'); 158 + if (iframe) { 159 + iframe.src = iframeUrl; 160 + } 161 + 162 + this.url = finalUrl; 163 + this.ts = ts; 164 + 165 + // Update hash if it was empty 166 + if (!url && finalUrl) { 167 + window.location.hash = ts ? `#${ts}/${finalUrl}` : `#${finalUrl}`; 168 + } 169 + } 170 + 171 + onIframeLoad(iframeUrl) { 172 + const m = iframeUrl.match(this.matchRx); 173 + if (!m) { 174 + console.log('[loadwabac] Iframe URL does not match pattern:', iframeUrl); 175 + return; 176 + } 177 + 178 + this.ts = m[1] || ''; 179 + this.url = m[2] || ''; 180 + 181 + console.log('[loadwabac] Iframe navigated to:', this.url); 182 + 183 + // Update hash to match iframe navigation 184 + const newHash = this.ts ? `#${this.ts}/${this.url}` : `#${this.url}`; 185 + if (window.location.hash !== newHash) { 186 + window.location.hash = newHash; 187 + } 188 + } 189 + } 190 + 191 + // Export for use in HTML 192 + if (typeof window !== 'undefined') { 193 + window.SeamsLiveProxy = SeamsLiveProxy; 194 + }
+66
vite.sure-client-inject.config.ts
··· 1 + import { defineConfig } from 'vite'; 2 + import path from 'path'; 3 + 4 + // Development server configuration (must match vite.sure-client.config.ts) 5 + const DEV_HOST = '127.0.0.1'; 6 + const DEV_PORT = 8081; 7 + 8 + // OAuth configuration 9 + const OAUTH_SCOPE = 'atproto transition:generic'; 10 + const DEV_REDIRECT_URI = `http://${DEV_HOST}:${DEV_PORT}/oauth-callback.html`; 11 + 12 + // Build the loopback client ID for development (AT Protocol OAuth spec) 13 + // Format: http://localhost?redirect_uri=<encoded_uri>&scope=<encoded_scope> 14 + // This special format tells the auth server to allow local development without fetching metadata 15 + const DEV_LOOPBACK_CLIENT_ID = 16 + `http://localhost?redirect_uri=${encodeURIComponent(DEV_REDIRECT_URI)}&scope=${encodeURIComponent(OAUTH_SCOPE)}`; 17 + 18 + // For production, use environment variables or the actual client metadata URL 19 + const isProd = process.env.NODE_ENV === 'production'; 20 + 21 + // Vite config for the injected seams-client.js script 22 + // Built as IIFE (self-contained, no ES module imports) for wabac.js injection 23 + export default defineConfig({ 24 + base: '/', 25 + publicDir: false, // Don't copy public/ to output 26 + build: { 27 + outDir: 'sure-client-proxy/dist', 28 + emptyOutDir: false, 29 + sourcemap: true, 30 + lib: { 31 + entry: path.resolve(__dirname, 'entrypoints/via-client/main.ts'), 32 + name: 'SeamsClient', 33 + fileName: () => 'seams-client.js', 34 + formats: ['iife'], 35 + }, 36 + rollupOptions: { 37 + output: { 38 + // Ensure everything is inlined 39 + inlineDynamicImports: true, 40 + }, 41 + }, 42 + }, 43 + resolve: { 44 + alias: { 45 + '@': path.resolve(__dirname, './'), 46 + }, 47 + }, 48 + define: { 49 + // Use loopback client ID format for development, real URL for production 50 + 'import.meta.env.VITE_OAUTH_CLIENT_ID': JSON.stringify( 51 + process.env.VITE_OAUTH_CLIENT_ID || (isProd ? 'https://sure.seams.so/client-metadata.json' : DEV_LOOPBACK_CLIENT_ID) 52 + ), 53 + 'import.meta.env.VITE_OAUTH_REDIRECT_URI': JSON.stringify( 54 + process.env.VITE_OAUTH_REDIRECT_URI || (isProd ? 'https://sure.seams.so/oauth-callback.html' : DEV_REDIRECT_URI) 55 + ), 56 + 'import.meta.env.VITE_OAUTH_SCOPE': JSON.stringify( 57 + process.env.VITE_OAUTH_SCOPE || OAUTH_SCOPE 58 + ), 59 + 'import.meta.env.VITE_BACKEND_URL': JSON.stringify( 60 + process.env.VITE_BACKEND_URL || 'https://seams.so' 61 + ), 62 + 'import.meta.env.BACKEND_URL': JSON.stringify( 63 + process.env.BACKEND_URL || 'https://seams.so' 64 + ), 65 + }, 66 + });
+72
vite.sure-client.config.ts
··· 1 + import { defineConfig } from 'vite'; 2 + import path from 'path'; 3 + 4 + // Development server configuration 5 + const DEV_HOST = '127.0.0.1'; 6 + const DEV_PORT = 8081; 7 + 8 + // OAuth configuration 9 + const OAUTH_SCOPE = 'atproto transition:generic'; 10 + const DEV_REDIRECT_URI = `http://${DEV_HOST}:${DEV_PORT}/oauth-callback.html`; 11 + 12 + // Build the loopback client ID for development (AT Protocol OAuth spec) 13 + // Format: http://localhost?redirect_uri=<encoded_uri>&scope=<encoded_scope> 14 + // This special format tells the auth server to allow local development without fetching metadata 15 + const DEV_LOOPBACK_CLIENT_ID = 16 + `http://localhost?redirect_uri=${encodeURIComponent(DEV_REDIRECT_URI)}&scope=${encodeURIComponent(OAUTH_SCOPE)}`; 17 + 18 + // For production, use environment variables or the actual client metadata URL 19 + const isProd = process.env.NODE_ENV === 'production'; 20 + 21 + const envDefines = { 22 + // Use loopback client ID format for development, real URL for production 23 + 'import.meta.env.VITE_OAUTH_CLIENT_ID': JSON.stringify( 24 + process.env.VITE_OAUTH_CLIENT_ID || (isProd ? 'https://sure.seams.so/client-metadata.json' : DEV_LOOPBACK_CLIENT_ID) 25 + ), 26 + 'import.meta.env.VITE_OAUTH_REDIRECT_URI': JSON.stringify( 27 + process.env.VITE_OAUTH_REDIRECT_URI || (isProd ? 'https://sure.seams.so/oauth-callback.html' : DEV_REDIRECT_URI) 28 + ), 29 + 'import.meta.env.VITE_OAUTH_SCOPE': JSON.stringify( 30 + process.env.VITE_OAUTH_SCOPE || OAUTH_SCOPE 31 + ), 32 + 'import.meta.env.VITE_BACKEND_URL': JSON.stringify( 33 + process.env.VITE_BACKEND_URL || 'https://seams.so' 34 + ), 35 + 'import.meta.env.BACKEND_URL': JSON.stringify( 36 + process.env.BACKEND_URL || 'https://seams.so' 37 + ), 38 + }; 39 + 40 + // Vite config for sure-client-proxy 41 + // Builds the shell (with embedded sidebar) and oauth HTML pages (ES modules) 42 + // The seams-client.js is built separately as IIFE (see vite.sure-client-inject.config.ts) 43 + export default defineConfig({ 44 + // Base path - files served from root of static server 45 + base: '/', 46 + publicDir: false, // Don't copy public/ to output 47 + build: { 48 + outDir: 'sure-client-proxy/dist', 49 + emptyOutDir: true, 50 + sourcemap: true, 51 + rollupOptions: { 52 + input: { 53 + // Shell - manages BackgroundWorker, storage, and renders Sidebar directly 54 + 'seams-shell': path.resolve(__dirname, 'sure-client-proxy/html/seams-shell.html'), 55 + // OAuth callback page (still needed for popup OAuth flow) 56 + 'oauth-callback': path.resolve(__dirname, 'sure-client-proxy/html/oauth-callback.html'), 57 + }, 58 + output: { 59 + entryFileNames: '[name].js', 60 + chunkFileNames: 'assets/[name]-[hash].js', 61 + assetFileNames: 'assets/[name]-[hash][extname]', 62 + format: 'es', 63 + }, 64 + }, 65 + }, 66 + resolve: { 67 + alias: { 68 + '@': path.resolve(__dirname, './'), 69 + }, 70 + }, 71 + define: envDefines, 72 + });
+3 -1
vite.via.config.ts
··· 1 1 import { defineConfig } from 'vite'; 2 2 import path from 'path'; 3 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 4 6 export default defineConfig({ 5 7 base: '/static/', 6 8 build: { ··· 10 12 rollupOptions: { 11 13 input: { 12 14 client: path.resolve(__dirname, 'entrypoints/via-client/main.ts'), 13 - 'seams-sidebar': path.resolve(__dirname, 'proxy/via-html/seams-sidebar.html'), 15 + // OAuth callback page (still needed for popup OAuth flow) 14 16 'oauth-callback': path.resolve(__dirname, 'proxy/via-html/oauth-callback.html'), 15 17 }, 16 18 output: {