learning_ai_common_plat/packages/broadcast-client/src/deep-link.ts
saravanakumardb1 18dd263797 feat(sdk): Push deep link routing for all platforms
- TypeScript: DeepLinkRouter with URL parsing and handler registration
- Swift: BLDeepLinkRouter with iOS URL handling and Logger integration
- Kotlin: DeepLinkRouter with Android Uri parsing and handler mapping
- Common screen constants: broadcasts, surveys, settings, profile, etc.
2026-03-03 08:33:56 -08:00

162 lines
3.7 KiB
TypeScript

/**
* Deep Link Router — TypeScript
* Handles routing from push notification deep links to app screens
*/
export interface DeepLinkRoute {
screen: string;
params?: Record<string, string>;
}
export type DeepLinkHandler = (route: DeepLinkRoute) => void;
/**
* Deep Link Router class
*/
export class DeepLinkRouter {
private handlers = new Map<string, DeepLinkHandler>();
private fallbackHandler?: DeepLinkHandler;
/**
* Register a handler for a specific screen
*/
register(screen: string, handler: DeepLinkHandler): void {
this.handlers.set(screen, handler);
}
/**
* Set a fallback handler for unregistered screens
*/
setFallback(handler: DeepLinkHandler): void {
this.fallbackHandler = handler;
}
/**
* Parse a deep link URL and extract route
*/
parseDeepLink(url: string): DeepLinkRoute | null {
try {
const urlObj = new URL(url);
// Handle app-specific URLs: myapp://screen/params
if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:') {
const pathParts = urlObj.pathname.split('/').filter(Boolean);
const screen = pathParts[0] || 'home';
const params: Record<string, string> = {};
// Parse query params
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return { screen, params };
}
// Handle web URLs with deep link params
const deepLinkParam = urlObj.searchParams.get('dl');
if (deepLinkParam) {
return this.parseDeepLink(deepLinkParam);
}
// Handle path-based routing: /screen/params
const pathParts = urlObj.pathname.split('/').filter(Boolean);
if (pathParts.length > 0) {
const screen = pathParts[0];
const params: Record<string, string> = {};
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return { screen, params };
}
return null;
} catch {
return null;
}
}
/**
* Handle a deep link route
*/
handle(route: DeepLinkRoute): boolean {
const handler = this.handlers.get(route.screen);
if (handler) {
handler(route);
return true;
}
if (this.fallbackHandler) {
this.fallbackHandler(route);
return true;
}
console.warn(`[DeepLink] No handler for screen: ${route.screen}`);
return false;
}
/**
* Process a deep link URL end-to-end
*/
process(url: string): boolean {
const route = this.parseDeepLink(url);
if (!route) {
console.warn(`[DeepLink] Failed to parse: ${url}`);
return false;
}
return this.handle(route);
}
}
/**
* Create a broadcast deep link URL
*/
export function createBroadcastDeepLink(
baseUrl: string,
screen: string,
params?: Record<string, string>,
broadcastId?: string
): string {
const url = new URL(baseUrl);
url.pathname = `/${screen}`;
if (params) {
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
}
if (broadcastId) {
url.searchParams.set('broadcastId', broadcastId);
}
return url.toString();
}
/**
* Common deep link screens for broadcast/survey flows
*/
export const DeepLinkScreens = {
// Broadcasts
BROADCAST_DETAIL: 'broadcast',
ANNOUNCEMENTS: 'announcements',
// Surveys
SURVEY: 'survey',
SURVEY_LIST: 'surveys',
// Product-specific (examples)
SETTINGS: 'settings',
PROFILE: 'profile',
UPGRADE: 'upgrade',
SUPPORT: 'support',
// Fallback
HOME: 'home',
} as const;
// Singleton instance for app-wide use
export const deepLinkRouter = new DeepLinkRouter();