From 33ce6bdb72cafa8b7c48c0c90d7998e32ca3c7f4 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Mon, 14 Jul 2025 20:49:40 -0600 Subject: [PATCH] fix: invite-one-accept deep link would not route properly --- src/interfaces/deepLinks.ts | 6 ++- src/main.capacitor.ts | 11 +++-- src/router/index.ts | 13 +++--- src/services/deepLinks.ts | 68 +++++++++++++++++-------------- src/views/DeepLinkErrorView.vue | 15 +++++-- src/views/InviteOneAcceptView.vue | 2 +- 6 files changed, 66 insertions(+), 49 deletions(-) diff --git a/src/interfaces/deepLinks.ts b/src/interfaces/deepLinks.ts index d9dbdbcc..f5838dc2 100644 --- a/src/interfaces/deepLinks.ts +++ b/src/interfaces/deepLinks.ts @@ -50,13 +50,15 @@ export const deepLinkSchemas = { jwt: z.string(), }), contacts: z.object({ - contacts: z.string(), // JSON string of contacts array + contactJwt: z.string().optional(), + inviteJwt: z.string().optional(), }), did: z.object({ did: z.string(), }), "invite-one-accept": z.object({ - jwt: z.string(), + // optional because A) it could be a query param, and B) the page displays an input if things go wrong + jwt: z.string().optional(), }), "onboard-meeting-members": z.object({ id: z.string(), diff --git a/src/main.capacitor.ts b/src/main.capacitor.ts index 3ac12d1f..42f1c38b 100644 --- a/src/main.capacitor.ts +++ b/src/main.capacitor.ts @@ -72,12 +72,11 @@ const handleDeepLink = async (data: { url: string }) => { await deepLinkHandler.handleDeepLink(data.url); } catch (error) { logger.error("[DeepLink] Error handling deep link: ", error); - handleApiError( - { - message: error instanceof Error ? error.message : safeStringify(error), - } as AxiosError, - "deep-link", - ); + let message: string = error instanceof Error ? error.message : safeStringify(error); + if (data.url) { + message += `\nURL: ${data.url}`; + } + handleApiError({ message } as AxiosError, "deep-link"); } }; diff --git a/src/router/index.ts b/src/router/index.ts index 010972bf..e43e104b 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -73,6 +73,11 @@ const routes: Array = [ name: "contacts", component: () => import("../views/ContactsView.vue"), }, + { + path: "/database-migration", + name: "database-migration", + component: () => import("../views/DatabaseMigration.vue"), + }, { path: "/did/:did?", name: "did", @@ -139,8 +144,9 @@ const routes: Array = [ component: () => import("../views/InviteOneView.vue"), }, { + // optional because A) it could be a query param, and B) the page displays an input if things go wrong path: "/invite-one-accept/:jwt?", - name: "InviteOneAcceptView", + name: "invite-one-accept", component: () => import("../views/InviteOneAcceptView.vue"), }, { @@ -148,11 +154,6 @@ const routes: Array = [ name: "logs", component: () => import("../views/LogView.vue"), }, - { - path: "/database-migration", - name: "database-migration", - component: () => import("../views/DatabaseMigration.vue"), - }, { path: "/new-activity", name: "new-activity", diff --git a/src/services/deepLinks.ts b/src/services/deepLinks.ts index 34d35cbb..8cd6db88 100644 --- a/src/services/deepLinks.ts +++ b/src/services/deepLinks.ts @@ -119,15 +119,6 @@ export class DeepLinkHandler { const [path, queryString] = parts[1].split("?"); const [routePath, ...pathParams] = path.split("/"); - // logger.info( - // "[DeepLink] Debug:", - // "Route Path:", - // routePath, - // "Path Params:", - // pathParams, - // "Query String:", - // queryString, - // ); // Validate route exists before proceeding if (!ROUTE_MAP[routePath]) { @@ -151,6 +142,11 @@ export class DeepLinkHandler { const routeConfig = ROUTE_MAP[routePath]; params[routeConfig.paramKey ?? "id"] = pathParams.join("/"); } + + // logConsoleAndDb( + // `[DeepLink] Debug: Route Path: ${routePath} Path Params: ${JSON.stringify(params)} Query String: ${JSON.stringify(query)}`, + // false, + // ); return { path: routePath, params, query }; } @@ -182,52 +178,65 @@ export class DeepLinkHandler { // Redirect to error page with information about the invalid link await this.router.replace({ name: "deep-link-error", + params, query: { originalPath: path, errorCode: "INVALID_ROUTE", - message: `The link you followed (${path}) is not supported`, + errorMessage: `The link you followed (${path}) is not supported`, + ...query, }, }); - throw { - code: "INVALID_ROUTE", - message: `Unsupported route: ${path}`, - }; + // This previously threw an error but we're redirecting so there's no need. + return; } // Continue with parameter validation as before... const schema = deepLinkSchemas[path as keyof typeof deepLinkSchemas]; + let validatedParams, validatedQuery; try { - const validatedParams = await schema.parseAsync({ - ...params, - ...query, + validatedParams = await schema.parseAsync(params); + validatedQuery = await schema.parseAsync(query); + } catch (error) { + // For parameter validation errors, provide specific error feedback + logConsoleAndDb(`[DeepLink] Invalid parameters for route name ${routeName} for path: ${path}: ${JSON.stringify(error)} ... with params: ${JSON.stringify(params)} ... and query: ${JSON.stringify(query)}`, true); + await this.router.replace({ + name: "deep-link-error", + params, + query: { + originalPath: path, + errorCode: "INVALID_PARAMETERS", + errorMessage: `The link parameters are invalid: ${(error as Error).message}`, + ...query, + }, }); + // This previously threw an error but we're redirecting so there's no need. + return; + } + + try { await this.router.replace({ name: routeName, params: validatedParams, - query, + query: validatedQuery, }); } catch (error) { + logConsoleAndDb(`[DeepLink] Error routing to route name ${routeName} for path: ${path}: ${JSON.stringify(error)} ... with validated params: ${JSON.stringify(validatedParams)} ... and validated query: ${JSON.stringify(validatedQuery)}`, true); // For parameter validation errors, provide specific error feedback await this.router.replace({ name: "deep-link-error", + params: validatedParams, query: { originalPath: path, - errorCode: "INVALID_PARAMETERS", - message: `The link parameters are invalid: ${(error as Error).message}`, + errorCode: "ROUTING_ERROR", + errorMessage: `Error routing to ${routeName}: ${(JSON.stringify(error))}`, + ...validatedQuery, }, }); - - throw { - code: "INVALID_PARAMETERS", - message: (error as Error).message, - details: error, - params: params, - query: query, - }; } + } /** @@ -239,7 +248,6 @@ export class DeepLinkHandler { */ async handleDeepLink(url: string): Promise { try { - logConsoleAndDb("[DeepLink] Processing URL: " + url, false); const { path, params, query } = this.parseDeepLink(url); // Ensure params is always a Record by converting undefined to empty string const sanitizedParams = Object.fromEntries( @@ -249,7 +257,7 @@ export class DeepLinkHandler { } catch (error) { const deepLinkError = error as DeepLinkError; logConsoleAndDb( - `[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.message}`, + `[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.details}`, true, ); diff --git a/src/views/DeepLinkErrorView.vue b/src/views/DeepLinkErrorView.vue index 3abb3ea1..f1c47f37 100644 --- a/src/views/DeepLinkErrorView.vue +++ b/src/views/DeepLinkErrorView.vue @@ -31,7 +31,7 @@

Supported Deep Links

  • - timesafari://{{ routeItem }}/:id + timesafari://{{ routeItem }}/:{{ deepLinkSchemaKeys[routeItem] }}
@@ -41,12 +41,19 @@