{"version":3,"sources":["../../../tools/browser/live.ts"],"sourcesContent":["/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n  /** Read-only monitoring (no interaction) */\n  readonly: { interactive: false } as LiveSessionOptions,\n  /** Interactive control (human-in-the-loop) */\n  interactive: { interactive: true } as LiveSessionOptions,\n  /** Watch-only without controls */\n  monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n  debugUrl: string,\n  options: LiveSessionOptions = {}\n): string {\n  if (!debugUrl) {\n    throw new Error(\n      'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n      'Contact support@morphllm.com if you need help.'\n    );\n  }\n\n  const normalized = normalizeLiveUrl(debugUrl);\n  const url = new URL(normalized);\n  \n  // Add query parameters for supported options\n  if (options.interactive !== undefined) {\n    url.searchParams.set('interactive', String(options.interactive));\n  }\n  \n  if (options.theme) {\n    url.searchParams.set('theme', options.theme);\n  }\n  \n  if (options.showControls !== undefined) {\n    url.searchParams.set('showControls', String(options.showControls));\n  }\n  \n  if (options.pageId) {\n    url.searchParams.set('pageId', options.pageId);\n  }\n  \n  if (options.pageIndex) {\n    url.searchParams.set('pageIndex', options.pageIndex);\n  }\n  \n  return url.toString();\n}\n\n/**\n * Convert a CDP WebSocket scheme to HTTPS.\n *\n * Browser-use's live viewer expects `wss=https://UUID.cdpN.browser-use.com`\n * but CDP URLs use `wss://`. This swaps the scheme.\n */\nfunction cdpToHttps(wsUrl: string): string {\n  return wsUrl.replace(/^wss:\\/\\//, 'https://').replace(/^ws:\\/\\//, 'http://');\n}\n\n/**\n * Normalize any debug URL into a valid browser-use live viewer URL.\n *\n * Handles three input formats:\n *  1. Already-correct `https://live.browser-use.com?wss=https://...` — pass through\n *  2. Already-correct but with wrong scheme `...?wss=wss://...` — fix the wss param\n *  3. Raw CDP URL `wss://UUID.cdpN.browser-use.com` — wrap into live viewer URL\n */\nfunction normalizeLiveUrl(debugUrl: string): string {\n  const trimmed = debugUrl.trim();\n  if (!trimmed) return trimmed;\n\n  // Case 3: raw CDP WebSocket URL → wrap into live viewer\n  if (trimmed.startsWith('wss://') || trimmed.startsWith('ws://')) {\n    return `https://live.browser-use.com?wss=${encodeURIComponent(cdpToHttps(trimmed))}`;\n  }\n\n  let url: URL;\n  try {\n    url = new URL(trimmed);\n  } catch {\n    return trimmed;\n  }\n\n  // Case 2: live viewer URL with wrong scheme in wss param → fix it\n  const wssParam = url.searchParams.get('wss');\n  if (wssParam && (wssParam.startsWith('wss://') || wssParam.startsWith('ws://'))) {\n    url.searchParams.set('wss', cdpToHttps(wssParam));\n  }\n\n  return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n *   interactive: true,\n *   width: '100%',\n *   height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n  debugUrl: string,\n  options: IframeOptions = {}\n): string {\n  const {\n    width = '100%',\n    height = '600px',\n    style = '',\n    className = '',\n    ...sessionOptions\n  } = options;\n\n  const src = buildLiveUrl(debugUrl, sessionOptions);\n  \n  // Convert numeric dimensions to pixels\n  const widthStr = typeof width === 'number' ? `${width}px` : width;\n  const heightStr = typeof height === 'number' ? `${height}px` : height;\n  \n  // Build style attribute\n  const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n  const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n  \n  // Build iframe attributes\n  const attributes = [\n    `src=\"${src}\"`,\n    `style=\"${fullStyle}\"`,\n  ];\n  \n  if (className) {\n    attributes.push(`class=\"${className}\"`);\n  }\n  \n  return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n  debugUrl: string,\n  options: IframeOptions = {}\n): string {\n  const iframe = buildLiveIframe(debugUrl, options);\n  return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n  optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n  if (!optionsOrPreset) {\n    return {};\n  }\n  \n  if (typeof optionsOrPreset === 'string') {\n    const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n    if (!preset) {\n      throw new Error(\n        `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n      );\n    }\n    return preset;\n  }\n  \n  return optionsOrPreset;\n}\n"],"mappings":"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","names":[]}