You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.1 KiB
189 lines
6.1 KiB
/**
|
|
* @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://<route>/<param>
|
|
* 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<void>}
|
|
*
|
|
* @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);
|
|
|