Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/core/src/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Platform } from './types';

export interface ParsedPayload {
[key: string]: any;
}

export interface AppHandler {

// The platform identifier (e.g., 'youtube', 'linkedin')

platform: Platform;


// Optional priority for the handler. Higher numbers are matched first.
// Defaults to 0.

priority?: number;


// Checks if the URL is supported by this handler.Should be fast and synchronous.

match(url: string): boolean;


// Parses the URL into a structured payload. Returns null if parsing fails.

parse(url: string): ParsedPayload | null;


// Builds a deep link or web URL for the specified OS.
buildLink(payload: ParsedPayload, os: 'ios' | 'android' | 'web'): string;
}
41 changes: 41 additions & 0 deletions packages/core/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Normalizes a URL string to a URL object.
* Adds 'https://' if protocol is missing.
*/
export function normalizeUrl(url: string): URL | null {
try {
let urlString = url.trim();
if (!urlString.startsWith('http://') && !urlString.startsWith('https://')) {
urlString = 'https://' + urlString;
}
return new URL(urlString);
} catch {
return null;
}
}

/**
* Extracts path segments from a URL object, ignoring empty segments.
*/
export function extractPathSegments(url: URL): string[] {
return url.pathname.split('/').filter((segment) => segment.length > 0);
}

/**
* Checks if the hostname matches any of the allowed domains.
* Handles 'www.' prefix automatically.
*/
export function matchHostname(url: URL, allowedDomains: string[]): boolean {
const hostname = url.hostname.toLowerCase().replace(/^www\./, '');
return allowedDomains.some((domain) => {
const normalizedDomain = domain.toLowerCase().replace(/^www\./, '');
return hostname === normalizedDomain || hostname.endsWith('.' + normalizedDomain);
});
}

/**
* Safely extracts a query parameter.
*/
export function getQueryParam(url: URL, param: string): string | null {
return url.searchParams.get(param);
}