合并原生壳桥接统一分支

合并 Expo 移动壳与 Tauri 桌面壳工程
保留创作主页、项目入口和现有生产发布脚本
同步 HostBridge 文档、依赖锁文件和原生壳门禁
This commit is contained in:
2026-06-22 22:28:31 +08:00
263 changed files with 72457 additions and 2263 deletions
+37
View File
@@ -3,7 +3,9 @@
import { describe, expect, it } from 'vitest';
import {
isAppHistoryState,
pushAppHistoryPath,
replaceAppHistoryPath,
resolvePathForSelectionStage,
resolveSelectionStageFromPath,
} from './appPageRoutes';
@@ -224,6 +226,41 @@ describe('appPageRoutes', () => {
);
});
it('keeps native app runtime context and marks app history entries', () => {
window.history.replaceState(
null,
'',
'/?clientRuntime=native_app&hostShell=tauri_desktop&hostPlatform=linux&hostVersion=0.1.0&bridgeVersion=1&hostCapabilities=host.getRuntime%2Chost.events%2Cnavigation.canGoBack',
);
pushAppHistoryPath('/creation/puzzle');
expect(window.location.pathname).toBe('/creation/puzzle');
expect(window.location.search).toBe(
'?clientRuntime=native_app&hostShell=tauri_desktop&hostPlatform=linux&hostVersion=0.1.0&bridgeVersion=1&hostCapabilities=host.getRuntime%2Chost.events%2Cnavigation.canGoBack',
);
expect(isAppHistoryState(window.history.state)).toBe(true);
});
it('replaces app history paths through the same runtime context rules', () => {
window.history.replaceState(
{ existing: true },
'',
'/creation/puzzle?clientRuntime=native_app&hostShell=expo_mobile&hostCapabilities=host.events%2Cnavigation.canGoBack',
);
replaceAppHistoryPath('/');
expect(window.location.pathname).toBe('/');
expect(window.location.search).toBe(
'?clientRuntime=native_app&hostShell=expo_mobile&hostCapabilities=host.events%2Cnavigation.canGoBack',
);
expect(window.history.state).toMatchObject({
existing: true,
});
expect(isAppHistoryState(window.history.state)).toBe(true);
});
it('clears creation restore query params when leaving the flow or switching flows', () => {
window.history.replaceState(
null,
+37 -6
View File
@@ -1,4 +1,5 @@
import type { SelectionStage } from '../components/platform-entry';
import { HOST_BRIDGE_PRESERVED_RUNTIME_CONTEXT_QUERY_KEYS } from '../../packages/shared/src/contracts/hostBridge';
import {
buildCreationUrlSearchFromParams,
isCreationRestorePath,
@@ -79,11 +80,9 @@ const ROUTE_STAGE_BY_PATH = new Map(
STAGE_ROUTE_ENTRIES.map(([stage, path]) => [path, stage] as const),
) as Map<string, SelectionStage>;
const APP_RUNTIME_CONTEXT_QUERY_KEYS = [
'clientType',
'clientRuntime',
'miniProgramEnv',
] as const;
const APP_RUNTIME_CONTEXT_QUERY_KEYS =
HOST_BRIDGE_PRESERVED_RUNTIME_CONTEXT_QUERY_KEYS;
export const APP_HISTORY_STATE_KEY = '__genarrativeAppHistoryEntry';
export function normalizeAppPath(pathname: string) {
const trimmedPathname = pathname.trim().toLowerCase();
@@ -160,6 +159,14 @@ export function isKnownMainAppPagePath(pathname: string) {
}
export function pushAppHistoryPath(path: string) {
writeAppHistoryPath(path, 'push');
}
export function replaceAppHistoryPath(path: string) {
writeAppHistoryPath(path, 'replace');
}
function writeAppHistoryPath(path: string, mode: 'push' | 'replace') {
const nextUrl = new URL(path, window.location.origin);
const normalizedPath = normalizeAppPath(nextUrl.pathname);
const nextSearch = buildPreservedAppSearch(
@@ -175,7 +182,31 @@ export function pushAppHistoryPath(path: string) {
}
// 页面阶段变化是用户可感知导航,写入 history 以支持前进后退。
window.history.pushState(null, '', nextRelativeUrl);
if (mode === 'replace') {
window.history.replaceState(buildAppHistoryState(), '', nextRelativeUrl);
return;
}
window.history.pushState(buildAppHistoryState(), '', nextRelativeUrl);
}
export function isAppHistoryState(state: unknown) {
return Boolean(
state &&
typeof state === 'object' &&
(state as Record<string, unknown>)[APP_HISTORY_STATE_KEY] === true,
);
}
function buildAppHistoryState() {
const currentState =
window.history.state && typeof window.history.state === 'object'
? window.history.state
: {};
return {
...currentState,
[APP_HISTORY_STATE_KEY]: true,
};
}
function buildPreservedAppSearch(