/** * @file Capacitor Main Entry Point * @author Matthew Raymer * * This file initializes the deep linking system for the TimeSafari app. * It sets up the connection between Capacitor's URL handling and our deep link processor. * * Deep Linking Flow: * 1. Capacitor receives URL open event * 2. Event is passed to DeepLinkHandler * 3. URL is validated and processed * 4. Router navigates to appropriate view * * Integration Points: * - Capacitor App plugin for URL handling * - Vue Router for navigation * - Error handling system * - Logging system * * Type Safety: * - Uses DeepLinkHandler for type-safe parameter processing * - Ensures type safety between Capacitor events and app routing * - Maintains type checking through the entire deep link flow * * @example * // URL open event from OS * timesafari://claim/123?view=details * // Processed and routed to appropriate view with type-safe parameters */ import { initializeApp } from "./main.common"; import { App as CapacitorApp } from "@capacitor/app"; import router from "./router"; import { handleApiError } from "./services/api"; import { AxiosError } from "axios"; import { DeepLinkHandler } from "./services/deepLinks"; import { logger, safeStringify } from "./utils/logger"; logger.log("[Capacitor] ๐Ÿš€ Starting initialization"); logger.log("[Capacitor] Platform:", process.env.VITE_PLATFORM); const app = initializeApp(); // Initialize API error handling for unhandled promise rejections window.addEventListener("unhandledrejection", (event) => { if (event.reason?.response) { handleApiError(event.reason, event.reason.config?.url || "unknown"); } }); const deepLinkHandler = new DeepLinkHandler(router); /** * Handles deep link routing for the application * Processes URLs in the format timesafari:/// * Maps incoming deep links to corresponding router paths with parameters * * @param {Object} data - Deep link data object * @param {string} data.url - The full deep link URL to process * @returns {Promise} * * @example * // Handles URLs like: * // timesafari://claim/01JMAAFZRNSRTQ0EBSD70A8E1H * // timesafari://project/abc123 * * @throws {Error} If URL format is invalid */ const handleDeepLink = async (data: { url: string }) => { const { url } = data; logger.info(`[Main] ๐ŸŒ Deeplink received from Capacitor: ${url}`); try { // Wait for router to be ready logger.info(`[Main] โณ Waiting for router to be ready...`); await router.isReady(); logger.info(`[Main] โœ… Router is ready, processing deeplink`); // Process the deeplink logger.info(`[Main] ๐Ÿš€ Starting deeplink processing`); await deepLinkHandler.handleDeepLink(url); logger.info(`[Main] โœ… Deeplink processed successfully`); } catch (error) { logger.error(`[Main] โŒ Deeplink processing failed:`, { url, error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, timestamp: new Date().toISOString(), }); // Log additional context for debugging logger.error(`[Main] ๐Ÿ” Debug context:`, { routerReady: router.isReady(), currentRoute: router.currentRoute.value, appMounted: app._instance?.isMounted, timestamp: new Date().toISOString(), }); // Fallback to original error handling let message: string = error instanceof Error ? error.message : safeStringify(error); if (url) { message += `\nURL: ${url}`; } handleApiError({ message } as AxiosError, "deep-link"); } }; // Function to register the deeplink listener const registerDeepLinkListener = async () => { try { logger.info( `[Main] ๐Ÿ”— Attempting to register deeplink handler with Capacitor`, ); // Check if Capacitor App plugin is available logger.info(`[Main] ๐Ÿ” Checking Capacitor App plugin availability...`); if (!CapacitorApp) { throw new Error("Capacitor App plugin not available"); } logger.info(`[Main] โœ… Capacitor App plugin is available`); // Check available methods on CapacitorApp logger.info( `[Main] ๐Ÿ” Capacitor App plugin methods:`, Object.getOwnPropertyNames(CapacitorApp), ); logger.info( `[Main] ๐Ÿ” Capacitor App plugin addListener method:`, typeof CapacitorApp.addListener, ); // Wait for router to be ready first await router.isReady(); logger.info( `[Main] โœ… Router is ready, proceeding with listener registration`, ); // Try to register the listener logger.info(`[Main] ๐Ÿงช Attempting to register appUrlOpen listener...`); const listenerHandle = await CapacitorApp.addListener( "appUrlOpen", handleDeepLink, ); logger.info( `[Main] โœ… appUrlOpen listener registered successfully with handle:`, listenerHandle, ); // Test the listener registration by checking if it's actually registered logger.info(`[Main] ๐Ÿงช Verifying listener registration...`); return listenerHandle; } catch (error) { logger.error(`[Main] โŒ Failed to register deeplink listener:`, { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, timestamp: new Date().toISOString(), }); throw error; } }; logger.log("[Capacitor] ๐Ÿš€ Mounting app"); app.mount("#app"); logger.info(`[Main] โœ… App mounted successfully`); // Register deeplink listener after app is mounted setTimeout(async () => { try { logger.info( `[Main] โณ Delaying listener registration to ensure Capacitor is ready...`, ); await registerDeepLinkListener(); logger.info(`[Main] ๐ŸŽ‰ Deep link system fully initialized!`); } catch (error) { logger.error(`[Main] โŒ Deep link system initialization failed:`, error); } }, 2000); // 2 second delay to ensure Capacitor is fully ready // Log app initialization status setTimeout(() => { logger.info(`[Main] ๐Ÿ“Š App initialization status:`, { routerReady: router.isReady(), currentRoute: router.currentRoute.value, appMounted: app._instance?.isMounted, timestamp: new Date().toISOString(), }); }, 1000);