Merge remote-tracking branch 'origin/master' into codex/wooden-fish-template

This commit is contained in:
2026-05-24 20:35:32 +08:00
12 changed files with 207 additions and 67 deletions

View File

@@ -7492,7 +7492,10 @@ export function PlatformEntryFlowShellImpl({
try {
const [detail, runResponse] = await Promise.all([
jumpHopClient.getWorkDetail(normalizedProfileId).catch(() => null),
jumpHopClient.startRun(normalizedProfileId),
jumpHopClient.startRun(
normalizedProfileId,
options.embedded ? RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS : {},
),
]);
if (detail?.item) {
setJumpHopWork(detail.item);
@@ -11666,8 +11669,6 @@ export function PlatformEntryFlowShellImpl({
if (
selectionStage !== 'platform' ||
platformBootstrap.platformTab !== 'home' ||
!platformBootstrap.isAuthenticated ||
!platformBootstrap.canReadProtectedData ||
platformBootstrap.isLoadingPlatform
) {
return;
@@ -11719,9 +11720,7 @@ export function PlatformEntryFlowShellImpl({
jumpHopRun,
isStartingRecommendEntry,
match3dRun,
platformBootstrap.canReadProtectedData,
platformBootstrap.isLoadingPlatform,
platformBootstrap.isAuthenticated,
platformBootstrap.platformTab,
puzzleRun,
recommendRuntimeEntries,

View File

@@ -2495,17 +2495,34 @@ test('logged out recommend cover opens login modal again', async () => {
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
});
test('logged out desktop recommend page renders cover only', () => {
test('logged out desktop recommend page renders runtime directly', () => {
mockDesktopLayout();
renderLoggedOutHomeView(vi.fn(), {
latestEntries: [puzzlePublicEntry],
activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1',
});
expect(document.querySelector('.platform-recommend-cover-only')).toBeTruthy();
expect(document.querySelector('.platform-recommend-cover-only')).toBeNull();
expect(screen.queryByText('今日游戏')).toBeNull();
expect(screen.queryByText('作品分类')).toBeNull();
expect(screen.queryByTestId('recommend-runtime')).toBeNull();
expect(screen.getByTestId('recommend-runtime')).toBeTruthy();
});
test('logged out recommend page can enter runtime without login gate', () => {
mockDesktopLayout();
const openLoginModal = vi.fn();
const onOpenGalleryDetail = vi.fn();
renderLoggedOutHomeView(openLoginModal, {
latestEntries: [puzzlePublicEntry],
activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1',
onOpenGalleryDetail,
recommendRuntimeContent: <div data-testid="recommend-runtime"></div>,
});
expect(screen.queryByRole('button', { name: / /u })).toBeNull();
expect(screen.getByTestId('recommend-runtime')).toBeTruthy();
expect(openLoginModal).not.toHaveBeenCalled();
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
});
test('logged in recommend page uses gated recommend detail callback', async () => {
@@ -2581,7 +2598,7 @@ test('logged in recommend page uses gated recommend detail callback', async () =
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
});
test('logged out mobile recommend page renders cover instead of runtime', () => {
test('logged out mobile recommend page renders runtime instead of cover', () => {
const onOpenGalleryDetail = vi.fn();
renderLoggedOutHomeView(
vi.fn(),
@@ -2593,13 +2610,13 @@ test('logged out mobile recommend page renders cover instead of runtime', () =>
'home',
);
expect(screen.queryByTestId('recommend-runtime')).toBeNull();
expect(document.querySelector('.platform-recommend-cover-only')).toBeTruthy();
expect(screen.getByTestId('recommend-runtime')).toBeTruthy();
expect(document.querySelector('.platform-recommend-cover-only')).toBeNull();
expect(
document.querySelector('.platform-public-work-card__cover'),
).toBeNull();
expect(screen.getAllByText('奇幻拼图').length).toBeGreaterThan(0);
fireEvent.click(screen.getByRole('button', { name: / /u }));
expect(screen.queryByRole('button', { name: / /u })).toBeNull();
expect(onOpenGalleryDetail).not.toHaveBeenCalled();
});
@@ -2611,7 +2628,8 @@ test('mobile recommend loading state is themed instead of hardcoded black', () =
recommendRuntimeContent: null,
});
expect(document.querySelector('.platform-recommend-cover-only')).toBeTruthy();
expect(document.querySelector('.platform-recommend-cover-only')).toBeNull();
expect(screen.getByText('加载中...')).toBeTruthy();
});
test('logged in recommend runtime preloads adjacent work previews and drag switches like video feed', () => {

View File

@@ -5273,16 +5273,6 @@ export function RpgEntryHomeView({
...
</div>
</section>
) : !isAuthenticated && activeRecommendEntry ? (
<section className="platform-recommend-runtime-panel">
<RecommendCoverOnlyCard
entry={activeRecommendEntry}
authorAvatarUrl={getPublicEntryAuthorAvatarUrl(
activeRecommendEntry,
)}
onClick={openActiveRecommendEntry}
/>
</section>
) : recommendRuntimeError ? (
<section className="platform-recommend-runtime-panel">
<button

View File

@@ -15,7 +15,11 @@ import type {
JumpHopWorkspaceCreateRequest,
JumpHopWorkSummaryResponse,
} from '../../../packages/shared/src/contracts/jumpHop';
import { type ApiRetryOptions, requestJson } from '../apiClient';
import {
type ApiRequestOptions,
type ApiRetryOptions,
requestJson,
} from '../apiClient';
import { createCreationAgentClient } from '../creation-agent';
const JUMP_HOP_API_BASE = '/api/creation/jump-hop/sessions';
@@ -26,6 +30,14 @@ const JUMP_HOP_RUNTIME_READ_RETRY: ApiRetryOptions = {
baseDelayMs: 120,
maxDelayMs: 360,
};
type JumpHopRuntimeRequestOptions = Pick<
ApiRequestOptions,
| 'authImpact'
| 'skipAuth'
| 'skipRefresh'
| 'notifyAuthStateChange'
| 'clearAuthOnUnauthorized'
>;
export type {
JumpHopActionRequest,
@@ -208,7 +220,10 @@ export async function publishJumpHopWork(profileId: string) {
return normalizeJumpHopWorkMutationResponse(response);
}
export async function startJumpHopRuntimeRun(profileId: string) {
export async function startJumpHopRuntimeRun(
profileId: string,
options: JumpHopRuntimeRequestOptions = {},
) {
return requestJson<JumpHopRunResponse>(
`${JUMP_HOP_RUNTIME_API_BASE}/runs`,
{
@@ -219,6 +234,13 @@ export async function startJumpHopRuntimeRun(profileId: string) {
body: JSON.stringify({ profileId }),
},
'启动跳一跳运行态失败',
{
authImpact: options.authImpact,
skipAuth: options.skipAuth,
skipRefresh: options.skipRefresh,
notifyAuthStateChange: options.notifyAuthStateChange,
clearAuthOnUnauthorized: options.clearAuthOnUnauthorized,
},
);
}