Files
Genarrative/apps/mobile-shell/src/shell/navigation.ts
T
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

84 lines
1.7 KiB
TypeScript

import { normalizeHostBridgeExternalUrl } from '../../../../packages/shared/src/contracts/hostBridge';
export type MobileShellExternalNavigator = {
canOpenURL: (url: string) => Promise<boolean>;
openURL: (url: string) => Promise<unknown>;
};
export function shouldOpenInMobileShellWebView(
rawUrl: string,
allowedOrigin: string,
) {
if (rawUrl === 'about:blank') {
return true;
}
if (
!rawUrl.startsWith('/') &&
!rawUrl.startsWith('#') &&
!/^[a-z][a-z0-9+.-]*:/i.test(rawUrl)
) {
return false;
}
try {
const url = new URL(rawUrl, allowedOrigin);
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
return false;
}
return url.origin === allowedOrigin;
} catch {
return false;
}
}
export function resolveMobileShellExternalUrl(rawUrl: string) {
return normalizeHostBridgeExternalUrl(rawUrl);
}
export async function openMobileShellExternalNavigation(
navigator: MobileShellExternalNavigator,
rawUrl: string,
) {
const externalUrl = resolveMobileShellExternalUrl(rawUrl);
if (!externalUrl) {
return false;
}
if (!(await navigator.canOpenURL(externalUrl))) {
return false;
}
await navigator.openURL(externalUrl);
return true;
}
export function shouldAcceptMobileShellHostBridgeMessage(
rawUrl: string,
allowedOrigin: string,
) {
return (
rawUrl !== 'about:blank' &&
shouldOpenInMobileShellWebView(rawUrl, allowedOrigin)
);
}
export function resolveMobileShellWebViewUrl(
rawUrl: string,
allowedOrigin: string,
) {
if (
rawUrl === 'about:blank' ||
!shouldOpenInMobileShellWebView(rawUrl, allowedOrigin)
) {
return null;
}
try {
return new URL(rawUrl, allowedOrigin).toString();
} catch {
return null;
}
}