Update spacetime-client bindings and frontend

Large update across server and web clients: regenerated/added many spacetime-client module bindings and input types (including new delete/work_delete input types and numerous procedure/reducer files), updates to server-rs API modules (bark_battle, jump_hop, wooden_fish, auth, module-runtime and shared contracts), and fixes in module-runtime behavior and domain logic. Frontend changes include new/updated components and tests (creative audio helpers, bark-battle/jump-hop/wooden-fish clients and views, unified generation pages, RPG entry views, and runtime shells), plus CSS and service updates. Documentation and operational notes updated (.hermes pitfalls and multiple PRD/docs) to cover daily-task refresh, banner asset fallback, recommend-key bug, and other platform behaviors. Tests and verification steps added/updated alongside these changes.
This commit is contained in:
2026-06-04 22:44:19 +08:00
parent 2678954627
commit 27b30f974b
326 changed files with 4374 additions and 2539 deletions

View File

@@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
import {
createBarkBattleDraft,
deleteBarkBattleWork,
generateAllBarkBattleImageAssets,
publishBarkBattleWork,
regenerateBarkBattleImageAsset,
@@ -73,6 +74,21 @@ describe('barkBattleCreationClient', () => {
);
});
it('deletes a draft or published work through runtime works API', async () => {
requestJsonMock.mockResolvedValueOnce({ items: [] });
await deleteBarkBattleWork('bark-battle-work-1');
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/runtime/bark-battle/works/bark-battle-work-1',
{ method: 'DELETE' },
'删除汪汪声浪作品失败',
expect.objectContaining({
retry: expect.objectContaining({ retryUnsafeMethods: true }),
}),
);
});
it('persists generated image slots into an existing draft config', async () => {
requestJsonMock.mockResolvedValueOnce({ draftId: 'draft-1' });

View File

@@ -290,6 +290,17 @@ export function listBarkBattleWorks(
);
}
export function deleteBarkBattleWork(workId: string) {
return requestJson<BarkBattleWorksResponse>(
`${BARK_BATTLE_RUNTIME_API_BASE}/works/${encodeURIComponent(workId)}`,
{ method: 'DELETE' },
'删除汪汪声浪作品失败',
{
retry: BARK_BATTLE_CREATION_WRITE_RETRY,
},
);
}
export function listBarkBattleGallery() {
return requestJson<BarkBattleWorksResponse>(
`${BARK_BATTLE_RUNTIME_API_BASE}/gallery`,
@@ -441,6 +452,7 @@ export async function generateAllBarkBattleImageAssets(payload: {
export const barkBattleCreationClient = {
createDraft: createBarkBattleDraft,
deleteWork: deleteBarkBattleWork,
generateAllImageAssets: generateAllBarkBattleImageAssets,
listGallery: listBarkBattleGallery,
listWorks: listBarkBattleWorks,

View File

@@ -7,6 +7,7 @@ export {
type BarkBattleImageGenerationFailures,
type BarkBattleUploadedAsset,
createBarkBattleDraft,
deleteBarkBattleWork,
generateAllBarkBattleImageAssets,
listBarkBattleGallery,
listBarkBattleWorks,

View File

@@ -0,0 +1,41 @@
import { beforeEach, expect, test, vi } from 'vitest';
const requestJsonMock = vi.hoisted(() => vi.fn());
const { createCreationAgentClientMock } = vi.hoisted(() => ({
createCreationAgentClientMock: vi.fn(),
}));
vi.mock('../creation-agent', () => ({
createCreationAgentClient: createCreationAgentClientMock,
}));
vi.mock('../apiClient', () => ({
requestJson: requestJsonMock,
}));
beforeEach(() => {
vi.resetModules();
createCreationAgentClientMock.mockReset();
createCreationAgentClientMock.mockReturnValue({
createSession: vi.fn(),
getSession: vi.fn(),
sendMessage: vi.fn(),
streamMessage: vi.fn(),
executeAction: vi.fn(),
});
requestJsonMock.mockReset();
});
test('jump hop delete work uses creation works endpoint', async () => {
const { jumpHopClient } = await import('./jumpHopClient');
requestJsonMock.mockResolvedValueOnce({ items: [] });
await jumpHopClient.deleteWork('jump-hop-profile-1');
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/creation/jump-hop/works/jump-hop-profile-1',
{ method: 'DELETE' },
'删除跳一跳作品失败',
);
});

View File

@@ -230,6 +230,14 @@ export async function publishJumpHopWork(profileId: string) {
return normalizeJumpHopWorkMutationResponse(response);
}
export async function deleteJumpHopWork(profileId: string) {
return requestJson<JumpHopWorksResponse>(
`${JUMP_HOP_WORKS_API_BASE}/${encodeURIComponent(profileId)}`,
{ method: 'DELETE' },
'删除跳一跳作品失败',
);
}
export async function startJumpHopRuntimeRun(
profileId: string,
options: JumpHopRuntimeRequestOptions = {},
@@ -302,6 +310,7 @@ export async function restartJumpHopRuntimeRun(
export const jumpHopClient = {
createSession: createJumpHopCreationSession,
deleteWork: deleteJumpHopWork,
getSession: getJumpHopCreationSession,
executeAction: executeJumpHopCreationAction,
getGalleryDetail: getJumpHopGalleryDetail,

View File

@@ -50,3 +50,16 @@ test('wooden fish list works uses creation works endpoint', async () => {
'读取敲木鱼作品列表失败',
);
});
test('wooden fish delete work uses creation works endpoint', async () => {
const { woodenFishClient } = await import('./woodenFishClient');
requestJsonMock.mockResolvedValueOnce({ items: [] });
await woodenFishClient.deleteWork('wooden-fish-profile-1');
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/creation/wooden-fish/works/wooden-fish-profile-1',
{ method: 'DELETE' },
'删除敲木鱼作品失败',
);
});

View File

@@ -233,6 +233,14 @@ export async function publishWoodenFishWork(profileId: string) {
return normalizeWoodenFishWorkMutationResponse(response);
}
export async function deleteWoodenFishWork(profileId: string) {
return requestJson<WoodenFishWorksResponse>(
`${WOODEN_FISH_WORKS_API_BASE}/${encodeURIComponent(profileId)}`,
{ method: 'DELETE' },
'删除敲木鱼作品失败',
);
}
export async function startWoodenFishRuntimeRun(
profileId: string,
options: WoodenFishRuntimeRequestOptions = {},
@@ -317,6 +325,7 @@ export async function finishWoodenFishRun(
export const woodenFishClient = {
checkpointRun: checkpointWoodenFishRun,
createSession: createWoodenFishCreationSession,
deleteWork: deleteWoodenFishWork,
executeAction: executeWoodenFishCreationAction,
finishRun: finishWoodenFishRun,
getGalleryDetail: getWoodenFishGalleryDetail,