{"version":3,"file":"router-CG_OcJt4.cjs","sources":["../../lib/vowel/platforms/generic/router.ts"],"sourcesContent":["/**\n * Generic Controlled Navigation Router\n * Handles navigation using cross-tab communication via BroadcastChannel\n * Opens navigation in a separate tab to keep voice agent running\n * \n * Platform-agnostic - works with any website\n */\n\nimport type { VowelRoute } from \"../../types\";\nimport type { RouterAdapter } from \"../../types/types\";\n\nexport interface ControlledNavigationRouterOptions {\n  /**\n   * BroadcastChannel name for cross-tab communication\n   * @default 'vowel-navigation'\n   */\n  channelName?: string;\n  \n  /**\n   * Custom config to send to controlled tab\n   */\n  config?: Record<string, any>;\n}\n\n/**\n * Router adapter for controlled navigation\n * Opens navigation in a dedicated tab to preserve voice agent session\n * \n * @example\n * ```ts\n * const router = new ControlledNavigationRouter();\n * router.setRoutes(discoveredRoutes);\n * \n * // Navigate to a page (opens in separate tab)\n * await router.navigate('/about');\n * ```\n */\nexport class ControlledNavigationRouter implements RouterAdapter {\n  private routes: VowelRoute[] = [];\n  private currentPath: string = \"\";\n  private channel: BroadcastChannel | null = null;\n  private controlledTabConnected: boolean = false;\n  private channelName: string;\n  private customConfig: Record<string, any>;\n\n  constructor(options: ControlledNavigationRouterOptions = {}) {\n    this.channelName = options.channelName || 'vowel-navigation';\n    this.customConfig = options.config || {};\n    \n    if (typeof window !== \"undefined\") {\n      this.currentPath = window.location.pathname;\n      this.setupNavigationListener();\n      \n      // Initialize BroadcastChannel for cross-tab communication\n      if (window.BroadcastChannel) {\n        this.channel = new BroadcastChannel(this.channelName);\n        console.log(`✅ ControlledNavigationRouter: BroadcastChannel initialized on channel '${this.channelName}'`);\n        console.log(\"   👂 Listening for controlled tab init messages...\");\n        \n        // Listen for messages from controlled tab\n        this.channel.onmessage = (event: MessageEvent) => {\n          const message = event.data;\n          console.log(`📨 ControlledNavigationRouter: Received message from controlled tab`);\n          console.log(`   📦 Message type: ${message.type}`);\n          console.log(`   ⏱️  Timestamp: ${new Date(message.timestamp).toISOString()}`);\n          \n          if (message.type === 'init') {\n            // Controlled tab is announcing itself\n            console.log(\"🎯 ControlledNavigationRouter: Controlled tab init message received\");\n            console.log(`   🔑 Detected via: ${message.detectedVia || 'unknown'}`);\n            console.log(`   📛 Window name: ${message.windowName}`);\n            console.log(`   📍 URL: ${message.url}`);\n            console.log(`   ⏱️  Init timestamp: ${message.timestamp}`);\n            console.log(`   📤 Preparing to send config response...`);\n            \n            // Send config back to controlled tab\n            this.sendConfig(message.requestTimestamp);\n          } else if (message.type === 'ack' && message.originalType === 'config') {\n            // Controlled tab confirms it received config\n            this.controlledTabConnected = true;\n            const roundTrip = Date.now() - message.requestTimestamp;\n            console.log(\"✅ ControlledNavigationRouter: Handshake complete - controlled tab configured and ready\");\n            console.log(`   ⏱️  Round-trip time: ${roundTrip}ms`);\n            console.log(`   🔗 Tab is now fully connected and listening for navigation commands`);\n          } else {\n            console.log(`ℹ️  ControlledNavigationRouter: Unhandled message type: ${message.type}`);\n          }\n        };\n      } else {\n        console.error(\"❌ ControlledNavigationRouter: BroadcastChannel not supported in this browser\");\n      }\n      \n      // Signal that this router needs a content window opened synchronously on start\n      (window as any).__vowelNeedsContentWindow = true;\n      console.log(\"✅ ControlledNavigationRouter: Set __vowelNeedsContentWindow flag\");\n    }\n  }\n\n  /**\n   * Send config message to controlled tab\n   * Called in response to init message from controlled tab\n   */\n  private sendConfig(requestTimestamp: number): void {\n    if (!this.channel) {\n      console.error(\"❌ ControlledNavigationRouter: Cannot send config - channel not initialized\");\n      return;\n    }\n    \n    const configMessage = {\n      type: 'config',\n      timestamp: Date.now(),\n      requestTimestamp: requestTimestamp, // For round-trip measurement\n      config: {\n        version: '1.0.0',\n        features: ['navigation'],\n        ...this.customConfig\n      }\n    };\n    \n    console.log(\"📡 ControlledNavigationRouter: Sending config message to controlled tab...\");\n    console.log(\"   📦 Config payload:\", JSON.stringify(configMessage.config, null, 2));\n    console.log(\"   ⏱️  Request timestamp:\", requestTimestamp);\n    console.log(\"   ⏱️  Response timestamp:\", configMessage.timestamp);\n    \n    this.channel.postMessage(configMessage);\n    \n    console.log(\"✅ ControlledNavigationRouter: Config message sent successfully\");\n    console.log(\"   ⏳ Waiting for ack from controlled tab...\");\n  }\n  \n  /**\n   * Get connection status for debugging\n   */\n  isControlledTabConnected(): boolean {\n    return this.controlledTabConnected;\n  }\n\n  /**\n   * Navigate to a path\n   * Opens URL in a controlled tab to preserve voice agent on main page\n   * \n   * @param path - Path to navigate to (can be relative, absolute, or full URL)\n   */\n  async navigate(path: string): Promise<void> {\n    console.log(\"🧭 Navigating to:\", path);\n\n    let targetUrl: string;\n\n    // Handle different types of navigation\n    if (path.startsWith(\"http://\") || path.startsWith(\"https://\")) {\n      targetUrl = path;\n    } else if (path.startsWith(\"/\")) {\n      // Absolute path - construct full URL with current origin\n      const currentOrigin = typeof window !== 'undefined' ? window.location.origin : '';\n      targetUrl = currentOrigin + path;\n    } else {\n      // Relative path - construct full URL\n      const currentUrl = new URL(window.location.href);\n      const newUrl = new URL(path, currentUrl.origin);\n      targetUrl = newUrl.href;\n    }\n\n    // Update current path\n    this.currentPath = path;\n\n    try {\n      // Send navigation command via BroadcastChannel\n      if (this.channel) {\n        if (!this.controlledTabConnected) {\n          console.warn(\"⚠️ ControlledNavigationRouter: Sending navigation to potentially disconnected tab\");\n          console.warn(\"   ℹ️  Tab may have been closed or not yet opened\");\n        }\n        \n        console.log(\"📡 ControlledNavigationRouter: Sending navigation command\");\n        console.log(\"   📍 Path:\", path);\n        console.log(\"   🔗 Full URL:\", targetUrl);\n        \n        this.channel.postMessage({\n          type: 'navigate',\n          path: path,\n          url: targetUrl,\n          timestamp: Date.now()\n        });\n        \n        console.log(\"✅ ControlledNavigationRouter: Navigation message sent successfully\");\n      } else {\n        console.error(\"❌ ControlledNavigationRouter: Cannot navigate - BroadcastChannel not available\");\n        throw new Error(\"BroadcastChannel not initialized\");\n      }\n    } catch (error) {\n      console.error(\"❌ ControlledNavigationRouter: Error sending navigation message:\", error);\n      throw error;\n    }\n\n    // Dispatch custom event for scripts\n    window.dispatchEvent(\n      new CustomEvent(\"vowel:navigation\", {\n        detail: { path, url: targetUrl },\n      })\n    );\n  }\n\n  /**\n   * Get current path from browser location\n   * \n   * @returns Current pathname\n   */\n  getCurrentPath(): string {\n    if (typeof window !== \"undefined\") {\n      this.currentPath = window.location.pathname;\n    }\n    return this.currentPath;\n  }\n\n  /**\n   * Get available routes\n   *\n   * @returns Available routes\n   */\n  getRoutes(): VowelRoute[] {\n    return this.routes;\n  }\n\n  /**\n   * Set routes (called after route discovery)\n   * \n   * @param routes - Available routes to set\n   */\n  setRoutes(routes: VowelRoute[]): void {\n    this.routes = routes;\n    console.log(`📋 Set ${routes.length} routes`);\n  }\n\n  /**\n   * Get router context for Vowel client\n   * Provides current location and route information\n   * \n   * @returns Router context object\n   */\n  getContext() {\n    return {\n      location: {\n        pathname: this.getCurrentPath(),\n        search: typeof window !== \"undefined\" ? window.location.search : \"\",\n        hash: typeof window !== \"undefined\" ? window.location.hash : \"\",\n      },\n      routes: this.routes,\n      currentPath: this.getCurrentPath(),\n    };\n  }\n\n  /**\n   * Setup navigation listener to track route changes\n   * Updates currentPath when navigation occurs\n   */\n  private setupNavigationListener(): void {\n    if (typeof window === \"undefined\") return;\n\n    // Listen for popstate (back/forward navigation)\n    window.addEventListener(\"popstate\", () => {\n      this.currentPath = window.location.pathname;\n    });\n\n    // Listen for hashchange\n    window.addEventListener(\"hashchange\", () => {\n      this.currentPath = window.location.pathname;\n    });\n  }\n}\n"],"names":[],"mappings":"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"}