Files
Genarrative/src/routing/activeAppPageRoutes.ts
T
kdletters 39aed2e486
Project CI / AI game creator shell Rust shard 1/4 (push) Failing after 18s
Project CI / AI game creator shell Rust shard 4/4 (push) Failing after 18s
Project CI / AI game creator shell Rust shard 2/4 (push) Failing after 19s
Project CI / AI game creator shell Rust shard 3/4 (push) Failing after 19s
Project CI / AI game creator shell Rust crates (push) Failing after 18s
Project CI / Native shell tests (push) Failing after 18s
Project CI / Backend tests (push) Failing after 18s
Project CI / AI game creator shell Rust smoke (push) Failing after 19s
Project CI / Frontend tests (push) Failing after 7s
Project CI / AI game creator shell web tests (push) Failing after 11s
Project CI / Repository checks (push) Failing after 11s
OSS 写入显式使用 v1 签名
ossutil v2 默认 v4 签名,缺 region 会直接失败\n总号写入与回读统一走 buildOssutilArgs,默认 --sign-version v1,可切 v4 并配合 AGC_OSS_REGION\n补充参数构造单测
2026-09-20 18:33:02 +08:00

136 lines
4.1 KiB
TypeScript

import { HOST_BRIDGE_PRESERVED_RUNTIME_CONTEXT_QUERY_KEYS } from '../../packages/shared/src/contracts/hostBridge';
import type { SelectionStage } from '../components/platform-entry/platformEntryActiveTypes';
export const EDITOR_CANVAS_PROJECT_ID_QUERY_PARAM = 'projectid';
const STAGE_ROUTE_ENTRIES = [
['platform', '/'],
['creation-home', '/creation'],
['project', '/project'],
['profile', '/profile'],
['image-editor', '/editor/canvas'],
['games', '/games'],
['game-detail', '/games/detail'],
['game-play', '/games/play'],
['game-mine', '/games/mine'],
['game-publish', '/games/publish'],
] as const satisfies readonly (readonly [SelectionStage, string])[];
export const APP_STAGE_ROUTES: Record<SelectionStage, string> =
Object.fromEntries(STAGE_ROUTE_ENTRIES) as Record<SelectionStage, string>;
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 =
HOST_BRIDGE_PRESERVED_RUNTIME_CONTEXT_QUERY_KEYS;
export const APP_HISTORY_STATE_KEY = '__genarrativeAppHistoryEntry';
export function normalizeAppPath(pathname: string) {
const trimmedPathname = pathname.trim().toLowerCase();
if (!trimmedPathname || trimmedPathname === '/') {
return '/';
}
return trimmedPathname.replace(/\/+$/u, '');
}
export function resolveSelectionStageFromPath(
pathname: string,
): SelectionStage {
return ROUTE_STAGE_BY_PATH.get(normalizeAppPath(pathname)) ?? 'platform';
}
export function resolveInitialSelectionStageFromPath(
pathname: string,
_isDesktopLayout: boolean,
): SelectionStage {
return resolveSelectionStageFromPath(pathname);
}
export function resolvePathForSelectionStage(stage: SelectionStage) {
return APP_STAGE_ROUTES[stage];
}
export function readEditorCanvasProjectIdFromLocationSearch(search: string) {
const params = new URLSearchParams(search);
return params.get(EDITOR_CANVAS_PROJECT_ID_QUERY_PARAM)?.trim() || null;
}
export function shouldRedirectEditorCanvasWithoutProject(
pathname: string,
search: string,
) {
return (
normalizeAppPath(pathname) === APP_STAGE_ROUTES['image-editor'] &&
!readEditorCanvasProjectIdFromLocationSearch(search)
);
}
export function isKnownMainAppPagePath(pathname: string) {
return ROUTE_STAGE_BY_PATH.has(normalizeAppPath(pathname));
}
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(
nextUrl.search,
window.location.search,
);
const nextRelativeUrl = `${normalizedPath}${nextSearch}`;
const currentRelativeUrl = `${normalizeAppPath(window.location.pathname)}${window.location.search}`;
if (currentRelativeUrl === nextRelativeUrl) {
return;
}
const state = buildAppHistoryState();
if (mode === 'replace') {
window.history.replaceState(state, '', nextRelativeUrl);
return;
}
window.history.pushState(state, '', 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(
explicitSearch: string,
currentSearch: string,
) {
const params = new URLSearchParams(explicitSearch);
const currentParams = new URLSearchParams(currentSearch);
APP_RUNTIME_CONTEXT_QUERY_KEYS.forEach((key) => {
if (!params.has(key) && currentParams.has(key)) {
params.set(key, currentParams.get(key) ?? '');
}
});
const serialized = params.toString();
return serialized ? `?${serialized}` : '';
}