Files
Genarrative/apps/mobile-shell/src/shell/deepLink.ts
T
kdletters 387a1c26e3 完成全量检查整改
清理已跟踪原始日志与个人本地配置
修复前后端有效门禁、测试和构建问题
补齐生产 Jenkins、SpacetimeDB 本地命令与文档约束
收紧图片编辑器状态、附件与媒体引用测试
排除已下线旧创作入口测试并清理 warning
2026-07-17 16:56:46 +08:00

113 lines
2.6 KiB
TypeScript

import {
buildMobileShellUrl,
type MobileShellBaseWebUrlOptions,
type MobileShellUrlOptions,
resolveMobileShellBaseWebUrl,
} from './url';
const supportedHosts = new Set(['open', 'app']);
type MobileShellDeepLinkResolutionStatus = 'default' | 'mapped' | 'rejected';
export type MobileShellDeepLinkResolution = {
status: MobileShellDeepLinkResolutionStatus;
url: string;
};
function extractPathFromNativeUrl(url: URL) {
if (supportedHosts.has(url.hostname)) {
return `${url.pathname}${url.search}${url.hash}`;
}
return `${url.hostname ? `/${url.hostname}` : ''}${url.pathname}${url.search}${url.hash}`;
}
function resolveTargetPath(rawUrl: string, webOrigin: string) {
try {
const url = new URL(rawUrl);
if (url.protocol === 'genarrative:') {
return extractPathFromNativeUrl(url);
}
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
return null;
}
if (url.origin !== webOrigin) {
return null;
}
return `${url.pathname}${url.search}${url.hash}`;
} catch {
if (!rawUrl.startsWith('/') && !rawUrl.startsWith('#')) {
return null;
}
try {
const relativeUrl = new URL(rawUrl, webOrigin);
if (relativeUrl.origin !== webOrigin) {
return null;
}
return `${relativeUrl.pathname}${relativeUrl.search}${relativeUrl.hash}`;
} catch {
return null;
}
}
}
export function buildMobileShellUrlFromDeepLink(
rawUrl: string | null | undefined,
baseWebUrl: string,
options: MobileShellUrlOptions,
baseWebUrlOptions: MobileShellBaseWebUrlOptions = {},
) {
return resolveMobileShellUrlFromDeepLink(
rawUrl,
baseWebUrl,
options,
baseWebUrlOptions,
).url;
}
export function resolveMobileShellUrlFromDeepLink(
rawUrl: string | null | undefined,
baseWebUrl: string,
options: MobileShellUrlOptions,
baseWebUrlOptions: MobileShellBaseWebUrlOptions = {},
): MobileShellDeepLinkResolution {
const normalizedBaseWebUrl = resolveMobileShellBaseWebUrl(
baseWebUrl,
baseWebUrlOptions,
);
const defaultUrl = buildMobileShellUrl(
normalizedBaseWebUrl,
options,
baseWebUrlOptions,
);
if (!rawUrl) {
return {
status: 'default',
url: defaultUrl,
};
}
const webOrigin = new URL(normalizedBaseWebUrl).origin;
const targetPath = resolveTargetPath(rawUrl, webOrigin);
if (!targetPath) {
return {
status: 'rejected',
url: defaultUrl,
};
}
return {
status: 'mapped',
url: buildMobileShellUrl(
new URL(targetPath, webOrigin).toString(),
options,
baseWebUrlOptions,
),
};
}