forked from jsnbuchanan/crowd-funder-for-time-pwa
feat(deepLinks): implement comprehensive deep linking system
- Add type-safe deep link parameter validation using Zod - Implement consistent error handling across all deep link routes - Add support for query parameters in deep links - Create comprehensive deep linking documentation - Add logging for deep link operations Security: - Validate all deep link parameters before processing - Sanitize and type-check query parameters - Add error boundaries around deep link handling - Implement route-specific parameter validation Testing: - Add parameter validation tests - Add error handling tests - Test query parameter support
This commit is contained in:
84
src/services/deepLinks.ts
Normal file
84
src/services/deepLinks.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Router } from "vue-router";
|
||||
import { deepLinkSchemas, DeepLinkParams } from "../types/deepLinks";
|
||||
import { logConsoleAndDb } from "../db";
|
||||
|
||||
interface DeepLinkError extends Error {
|
||||
code: string;
|
||||
details?: unknown;
|
||||
}
|
||||
|
||||
export class DeepLinkHandler {
|
||||
private router: Router;
|
||||
|
||||
constructor(router: Router) {
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes incoming deep links and routes them appropriately
|
||||
* @param url The deep link URL to process
|
||||
*/
|
||||
async handleDeepLink(url: string): Promise<void> {
|
||||
try {
|
||||
logConsoleAndDb("[DeepLink] Processing URL: " + url, false);
|
||||
|
||||
const { path, params, query } = this.parseDeepLink(url);
|
||||
await this.validateAndRoute(path, params, query);
|
||||
|
||||
} catch (error) {
|
||||
const deepLinkError = error as DeepLinkError;
|
||||
logConsoleAndDb(
|
||||
`[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.message}`,
|
||||
true
|
||||
);
|
||||
|
||||
throw {
|
||||
code: deepLinkError.code || 'UNKNOWN_ERROR',
|
||||
message: deepLinkError.message,
|
||||
details: deepLinkError.details
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes the deep link to appropriate view with validated parameters
|
||||
*/
|
||||
private async validateAndRoute(
|
||||
path: string,
|
||||
params: Record<string, string>,
|
||||
query: Record<string, string>
|
||||
): Promise<void> {
|
||||
const routeMap: Record<string, string> = {
|
||||
claim: 'claim',
|
||||
'claim-cert': 'claim-cert',
|
||||
'claim-add-raw': 'claim-add-raw',
|
||||
'contact-edit': 'contact-edit',
|
||||
'contact-import': 'contact-import',
|
||||
project: 'project',
|
||||
'invite-one-accept': 'invite-one-accept',
|
||||
'offer-details': 'offer-details',
|
||||
'confirm-gift': 'confirm-gift'
|
||||
};
|
||||
|
||||
const routeName = routeMap[path];
|
||||
if (!routeName) {
|
||||
throw {
|
||||
code: 'INVALID_ROUTE',
|
||||
message: `Unsupported route: ${path}`
|
||||
};
|
||||
}
|
||||
|
||||
// Validate parameters based on route type
|
||||
const schema = deepLinkSchemas[path as keyof typeof deepLinkSchemas];
|
||||
const validatedParams = await schema.parseAsync({
|
||||
...params,
|
||||
...query
|
||||
});
|
||||
|
||||
await this.router.replace({
|
||||
name: routeName,
|
||||
params: validatedParams,
|
||||
query
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user