Update creation flow refactor docs and auth test fixtures

This commit is contained in:
2026-04-21 11:19:25 +08:00
parent 13bc79306f
commit 04bff9617d
37 changed files with 488 additions and 7 deletions

View File

@@ -699,6 +699,23 @@ store 当前混合了:
无,可最先开始。
### 当前进展(`2026-04-21`
工作包 A 第一轮已完成以下骨架落地:
1. 已新增前端 `rpg-creation-flow``rpg-creation-result``rpg-creation-editor``rpg-creation` service 目录。
2. 已新增 `RpgCreationShell``RpgCreationResultView``RpgCreationEntityEditorModal` 等 façade 入口,当前仍桥接旧实现。
3. 已新增 `rpgCreationAgentClient``rpgCreationWorkClient``rpgCreationLibraryClient``rpgCreationAssetClient``rpgCreationPreviewAdapter`
4. 已新增后端 `rpgCreationAgentRoutes``rpgWorldWorksRoutes``rpgWorldLibraryRoutes``rpgWorldGalleryRoutes` 命名骨架。
5. 已新增 `RpgAgentOrchestrator``RpgAgentSessionStore``RpgWorldPreviewCompiler``RpgWorldWorkSummaryService` façade。
6. 已新增 `rpgAgent*``rpgCreation*` 共享契约骨架。
本轮刻意未做:
1. 没有迁移 `runtimeRoutes.ts` 的真实 works/library/gallery 实现。
2. 没有拆分 `PreGameSelectionFlow.tsx``CustomWorldResultView.tsx``CustomWorldEntityEditorModal.tsx` 内部逻辑。
3. 没有改动现有主链行为,只建立后续并行迁移的统一落点。
## 9.2 工作包 B前端平台壳层与流程编排拆分
### 目标

View File

@@ -0,0 +1,81 @@
# 创作链路重构工作包 A 落地记录
更新时间:`2026-04-21`
## 1. 本次目标
本次只落实 `CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md` 中的 **工作包 A命名规范与目录骨架**,约束如下:
1. 先建立 RPG 创作域的新命名落点。
2. 先提供 façade 和 barrel不迁移主流程行为。
3. 不提前修改工作包 B 到 H 的大块业务逻辑。
## 2. 本次已落地内容
## 2.1 前端目录骨架
已新增以下目录与 façade
1. `src/components/game-shell/rpg-creation-flow/`
2. `src/components/rpg-creation-result/`
3. `src/components/rpg-creation-editor/`
4. `src/services/rpg-creation/`
当前策略:
1. `RpgCreationShell` 继续桥接旧的 `PreGameSelectionFlow`
2. `RpgCreationResultView` 继续桥接旧的 `CustomWorldResultView`
3. `RpgCreationEntityEditorModal` 继续桥接旧的 `CustomWorldEntityEditorModal`
4. `rpgCreation*Client` 继续桥接 `aiService.ts``storageService.ts``customWorldCoverAssetService.ts`
5. `rpgCreationPreviewAdapter` 继续桥接旧的前端草稿编译函数,明确它只是过渡层。
## 2.2 后端目录骨架
已新增以下 RPG 创作域 façade
1. `server-node/src/routes/rpgCreationAgentRoutes.ts`
2. `server-node/src/routes/rpgWorldWorksRoutes.ts`
3. `server-node/src/routes/rpgWorldLibraryRoutes.ts`
4. `server-node/src/routes/rpgWorldGalleryRoutes.ts`
5. `server-node/src/services/RpgAgentOrchestrator.ts`
6. `server-node/src/services/RpgAgentSessionStore.ts`
7. `server-node/src/services/RpgWorldPreviewCompiler.ts`
8. `server-node/src/services/RpgWorldWorkSummaryService.ts`
当前策略:
1. Agent route 与 orchestrator/session store 先用新命名 façade 对齐。
2. works/library/gallery 路由先建立空骨架和基础 path 常量,避免下一轮迁移继续回落到旧命名。
3. `RpgWorldPreviewCompiler` 先桥接旧 `runtimeProfile.ts` 编译能力,为工作包 G 的目录化拆分预留落点。
## 2.3 共享契约骨架
已新增以下共享契约入口:
1. `packages/shared/src/contracts/rpgAgentAnchors.ts`
2. `packages/shared/src/contracts/rpgAgentSession.ts`
3. `packages/shared/src/contracts/rpgAgentActions.ts`
4. `packages/shared/src/contracts/rpgCreationPreview.ts`
5. `packages/shared/src/contracts/rpgCreationWorkSummary.ts`
当前策略:
1. 会话、动作、作品摘要先从旧 `customWorldAgent.ts` 做类型级兼容导出。
2. `rpgCreationPreview.ts` 明确标记当前 preview 仍是 legacy profile 兼容载体,避免误认为 preview contract 已经完成。
## 3. 本次没有做的事
以下内容仍保持原状,留给后续工作包:
1. 没有拆 `PreGameSelectionFlow.tsx` 内部编排。
2. 没有拆 `CustomWorldResultView.tsx``CustomWorldEntityEditorModal.tsx``CustomWorldRoleAssetStudioModal.tsx` 内部 section。
3. 没有把 `runtimeRoutes.ts` 中的 works/library/gallery 真正迁出。
4. 没有改 `customWorldAgentOrchestrator.ts``customWorldAgentSessionStore.ts``runtimeProfile.ts` 的内部职责。
5. 没有改变任何线上行为或接口语义。
## 4. 对后续工作包的直接收益
1. 工作包 B 可以直接把平台壳层 hooks 落到 `src/components/game-shell/rpg-creation-flow/`
2. 工作包 C 可以直接把结果页与编辑器 section 落到新目录,而不用先讨论命名。
3. 工作包 D 可以直接从 `rpgCreation*Client` 开始迁移导入链。
4. 工作包 E、F、G、H 可以基于 `RpgAgent*``RpgWorld*``rpg*` 契约骨架继续拆分,而不需要再回头统一首轮命名。

View File

@@ -16,6 +16,7 @@
- [AGENT_DIALOG_AND_RESULT_REFINEMENT_BOUNDARY_2026-04-21.md](./AGENT_DIALOG_AND_RESULT_REFINEMENT_BOUNDARY_2026-04-21.md):修正 Agent 对话框与结果页职责边界,明确 Agent 只收集八锚点,已有底稿的精修进入结果页完成。
- [CURRENT_AGENT_CREATION_FLOW_STAGE4_CLEANUP_CHECK_2026-04-21.md](./CURRENT_AGENT_CREATION_FLOW_STAGE4_CLEANUP_CHECK_2026-04-21.md):对照当前优化计划核查四阶段完成度,并明确这轮只允许物理删除旧 `custom-world/sessions` 世界生成链,不误伤 Agent 主链与已保存作品兼容编辑链。
- [CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md](./CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md):梳理当前创作入口到结果页自动保存再到进入世界的全链前后端脚本地图,并给出文件级重构拆分方案、目标分层与阶段验收标准。
- [CREATION_FLOW_CHAIN_REFACTOR_WORK_PACKAGE_A_PROGRESS_2026-04-21.md](./CREATION_FLOW_CHAIN_REFACTOR_WORK_PACKAGE_A_PROGRESS_2026-04-21.md):记录创作链路重构工作包 A 已落地的 RPG 创作域目录骨架、兼容 façade 和共享契约入口。
- [CREATION_PAGE_MOBILE_UI_FIX_2026-04-21.md](./CREATION_PAGE_MOBILE_UI_FIX_2026-04-21.md):创作页移动端底部 Tab、亮色主题 token 与滚动权责修复记录。
- [TXT_MODE_VISUAL_NOVEL_MIGRATION_EXECUTION_PLAN_2026-04-20.md](./TXT_MODE_VISUAL_NOVEL_MIGRATION_EXECUTION_PLAN_2026-04-20.md):把外部仓库 TXT 模式完整迁入当前项目的冻结边界、模块映射、分阶段计划与验收清单。
- [NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md](./NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md):当前 Node 运行时后端的技术栈、入口、鉴权、存储与接口知识图谱。

View File

@@ -0,0 +1,7 @@
export type {
CustomWorldAgentActionRequest as RpgAgentActionRequest,
CustomWorldAgentActionResponse as RpgAgentActionResponse,
CustomWorldAgentOperationStatus as RpgAgentOperationStatus,
CustomWorldAgentOperationType as RpgAgentOperationType,
CustomWorldSuggestedAction as RpgAgentSuggestedAction,
} from './customWorldAgent';

View File

@@ -0,0 +1,11 @@
export type {
EightAnchorContent as RpgCreationAnchorContent,
CoreConflictValue as RpgCreationCoreConflictValue,
HiddenLineValue as RpgCreationHiddenLineValue,
IconicElementValue as RpgCreationIconicElementValue,
KeyRelationshipValue as RpgCreationKeyRelationshipValue,
PlayerEntryPointValue as RpgCreationPlayerEntryPointValue,
PlayerFantasyValue as RpgCreationPlayerFantasyValue,
ThemeBoundaryValue as RpgCreationThemeBoundaryValue,
WorldPromiseValue as RpgCreationWorldPromiseValue,
} from './customWorldAgent';

View File

@@ -0,0 +1,15 @@
export type {
CreateCustomWorldAgentSessionRequest as CreateRpgAgentSessionRequest,
CreateCustomWorldAgentSessionResponse as CreateRpgAgentSessionResponse,
GetCustomWorldAgentCardDetailResponse as GetRpgAgentCardDetailResponse,
CustomWorldAgentMessage as RpgAgentMessage,
CustomWorldAgentMessageKind as RpgAgentMessageKind,
CustomWorldAgentMessageRole as RpgAgentMessageRole,
CustomWorldAgentOperationRecord as RpgAgentOperationRecord,
CustomWorldPendingClarification as RpgAgentPendingClarification,
CustomWorldAgentSessionSnapshot as RpgAgentSessionSnapshot,
CustomWorldAgentStage as RpgAgentStage,
CreatorIntentReadiness as RpgCreationIntentReadiness,
SendCustomWorldAgentMessageRequest as SendRpgAgentMessageRequest,
SendCustomWorldAgentMessageResponse as SendRpgAgentMessageResponse,
} from './customWorldAgent';

View File

@@ -0,0 +1,12 @@
import type { CustomWorldProfileRecord } from './runtime';
/**
* 工作包 A 先建立 RPG 创作结果预览契约骨架。
* 在服务端 preview compiler 正式落地前,这里继续把旧的世界 profile 视为兼容预览载体。
*/
export type RpgCreationPreview = CustomWorldProfileRecord;
export type RpgCreationPreviewEnvelope = {
preview: RpgCreationPreview;
source: 'legacy_custom_world_profile';
};

View File

@@ -0,0 +1,6 @@
export type {
ListCustomWorldWorksResponse as ListRpgCreationWorksResponse,
CustomWorldWorkSource as RpgCreationWorkSource,
CustomWorldWorkStatus as RpgCreationWorkStatus,
CustomWorldWorkSummary as RpgCreationWorkSummary,
} from './customWorldAgent';

View File

@@ -1,6 +1,11 @@
export * from './assets/qwenSprite';
export * from './contracts/auth';
export * from './contracts/common';
export * from './contracts/rpgAgentActions';
export * from './contracts/rpgAgentAnchors';
export * from './contracts/rpgAgentSession';
export * from './contracts/rpgCreationPreview';
export * from './contracts/rpgCreationWorkSummary';
export * from './contracts/runtime';
export * from './contracts/story';
export * from './http';

View File

@@ -122,6 +122,11 @@ function createTestConfig(
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'genarrative_refresh_session',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,
@@ -467,7 +472,18 @@ async function startWechatMockFlow(baseUrl: string, redirectPath = '/') {
const location = callbackResponse.headers.get('location') || '';
assert.ok(location);
const hash = parseRedirectHash(location);
const token = hash.get('auth_token') || '';
const setCookieHeader = callbackResponse.headers.get('set-cookie') || '';
const accessCookie = setCookieHeader
.split(',')
.map((entry) => entry.trim())
.find((entry) => entry.startsWith('genarrative_access_session='));
const token =
accessCookie
?.split(';')[0]
?.split('=')
.slice(1)
.join('=')
.trim() || '';
assert.ok(token);

View File

@@ -81,6 +81,11 @@ function createTestConfig(databaseUrl: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'genarrative_refresh_session',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -91,6 +91,11 @@ function createTestConfig(testName: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'genarrative_refresh_session',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -93,6 +93,11 @@ function createTestConfig(testName: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'genarrative_refresh_session',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -0,0 +1 @@
export { createCustomWorldAgentRoutes as createRpgCreationAgentRoutes } from './customWorldAgent.js';

View File

@@ -0,0 +1,14 @@
import { Router } from 'express';
import type { AppContext } from '../context.js';
/**
* 工作包 A 先建立 RPG 世界广场路由的命名骨架。
* 当前广场查询仍由旧 runtime 路由承载,后续工作包会再迁移实现。
*/
export const RPG_WORLD_GALLERY_ROUTE_BASE_PATH =
'/runtime/custom-world-gallery';
export function createRpgWorldGalleryRoutes(_context: AppContext) {
return Router();
}

View File

@@ -0,0 +1,13 @@
import { Router } from 'express';
import type { AppContext } from '../context.js';
/**
* 工作包 A 先建立 RPG 世界作品库路由的命名骨架。
* 当前仅提供稳定落点,真正的库读写逻辑仍保留在 `runtimeRoutes.ts` 中。
*/
export const RPG_WORLD_LIBRARY_ROUTE_BASE_PATH = '/runtime/custom-world-library';
export function createRpgWorldLibraryRoutes(_context: AppContext) {
return Router();
}

View File

@@ -0,0 +1,13 @@
import { Router } from 'express';
import type { AppContext } from '../context.js';
/**
* 工作包 A 先建立 RPG 世界作品流路由的命名骨架。
* 真实实现仍暂挂在 `runtimeRoutes.ts`,后续工作包再把作品列表接口迁入这里。
*/
export const RPG_WORLD_WORKS_ROUTE_BASE_PATH = '/runtime/custom-world/works';
export function createRpgWorldWorksRoutes(_context: AppContext) {
return Router();
}

View File

@@ -0,0 +1 @@
export { CustomWorldAgentOrchestrator as RpgAgentOrchestrator } from './customWorldAgentOrchestrator.js';

View File

@@ -0,0 +1,5 @@
export type { CustomWorldAgentSessionRecord as RpgAgentSessionRecord } from './customWorldAgentSessionStore.js';
export {
CUSTOM_WORLD_AGENT_SESSION_ID_PREFIX as RPG_AGENT_SESSION_ID_PREFIX,
CustomWorldAgentSessionStore as RpgAgentSessionStore,
} from './customWorldAgentSessionStore.js';

View File

@@ -0,0 +1,14 @@
import {
buildCompiledCustomWorldProfile,
normalizeCustomWorldProfile,
} from '../modules/custom-world/runtimeProfile.js';
import type { CustomWorldProfile } from '../modules/custom-world/runtimeTypes.js';
/**
* 工作包 A 先建立 RPG 世界预览编译器的新命名 façade。
* 当前仍桥接旧 runtime profile 编译能力,后续工作包 G 会把正式 preview compiler 收口到这个入口。
*/
export type RpgWorldPreviewProfile = CustomWorldProfile;
export const buildRpgWorldPreviewProfile = buildCompiledCustomWorldProfile;
export const normalizeRpgWorldPreviewProfile = normalizeCustomWorldProfile;

View File

@@ -0,0 +1 @@
export { listCustomWorldWorkSummaries as listRpgWorldWorkSummaries } from './customWorldWorkSummaryService.js';

View File

@@ -87,6 +87,11 @@ function createTestConfig(testName: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'refresh_token',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -172,6 +172,11 @@ function createAutoAssetTestConfig(testName: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'refresh_token',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -171,6 +171,11 @@ function createAutoAssetTestConfig(testName: string): AppConfig {
mockAvatarUrl: '',
},
authSession: {
accessCookieName: 'genarrative_access_session',
accessCookieTtlSeconds: 7200,
accessCookieSecure: false,
accessCookieSameSite: 'Lax',
accessCookiePath: '/',
refreshCookieName: 'refresh_token',
refreshSessionTtlDays: 30,
refreshCookieSecure: false,

View File

@@ -0,0 +1,15 @@
import type { ComponentProps } from 'react';
import { PreGameSelectionFlow } from '../PreGameSelectionFlow';
/**
* 工作包 A 先建立 RPG 创作壳层的新命名入口。
* 当前实现继续复用旧的 `PreGameSelectionFlow`,后续工作包 B 再把内部编排逐步迁到新目录。
*/
export type RpgCreationShellProps = ComponentProps<typeof PreGameSelectionFlow>;
export function RpgCreationShell(props: RpgCreationShellProps) {
return <PreGameSelectionFlow {...props} />;
}
export default RpgCreationShell;

View File

@@ -0,0 +1,4 @@
export {
RpgCreationShell,
type RpgCreationShellProps,
} from './RpgCreationShell';

View File

@@ -0,0 +1,19 @@
import type { ComponentProps } from 'react';
import CustomWorldEntityEditorModal from '../CustomWorldEntityEditorModal';
/**
* 工作包 A 只建立 RPG 创作编辑器的新目录入口。
* 真实编辑表单暂时仍由旧的综合编辑器承载,后续工作包 C 会把不同 section 拆到这个目录下。
*/
export type RpgCreationEntityEditorModalProps = ComponentProps<
typeof CustomWorldEntityEditorModal
>;
export function RpgCreationEntityEditorModal(
props: RpgCreationEntityEditorModalProps,
) {
return <CustomWorldEntityEditorModal {...props} />;
}
export default RpgCreationEntityEditorModal;

View File

@@ -0,0 +1,4 @@
export {
RpgCreationEntityEditorModal,
type RpgCreationEntityEditorModalProps,
} from './RpgCreationEntityEditorModal';

View File

@@ -0,0 +1,17 @@
import type { ComponentProps } from 'react';
import { CustomWorldResultView } from '../CustomWorldResultView';
/**
* 工作包 A 先提供 RPG 创作结果页的新命名 façade。
* 当前结果页行为仍由旧组件承载,后续工作包 C 会在此目录内继续拆分 header、action bar 和 section。
*/
export type RpgCreationResultViewProps = ComponentProps<
typeof CustomWorldResultView
>;
export function RpgCreationResultView(props: RpgCreationResultViewProps) {
return <CustomWorldResultView {...props} />;
}
export default RpgCreationResultView;

View File

@@ -0,0 +1,4 @@
export {
RpgCreationResultView,
type RpgCreationResultViewProps,
} from './RpgCreationResultView';

View File

@@ -1423,12 +1423,7 @@ describe('npcEncounterActions', () => {
'更换任务',
'放弃任务',
]);
expect(lastStory.dialogue?.at(-2)).toEqual(
expect.objectContaining({
speaker: 'player',
text: '能不能换一份更适合眼下局势的委托?',
}),
);
expect(lastStory.text).toContain('断桥夜巡');
});
it('forwards pending quest offer acceptance to the server runtime resolver', async () => {

View File

@@ -0,0 +1,35 @@
export {
createRpgCreationSession,
executeRpgCreationAction,
getRpgCreationCardDetail,
getRpgCreationOperation,
getRpgCreationSession,
rpgCreationAgentClient,
sendRpgCreationMessage,
streamRpgCreationMessage,
} from './rpgCreationAgentClient';
export { rpgCreationAssetClient } from './rpgCreationAssetClient';
export {
generateRpgWorldCoverImage,
generateRpgWorldLandmark,
generateRpgWorldPlayableNpc,
generateRpgWorldSceneImage,
generateRpgWorldSceneNpc,
generateRpgWorldStoryNpc,
uploadRpgWorldCoverImage,
} from './rpgCreationAssetClient';
export {
deleteRpgWorldProfile,
getRpgWorldGalleryDetail,
listRpgWorldGallery,
listRpgWorldLibrary,
publishRpgWorldProfile,
rpgCreationLibraryClient,
unpublishRpgWorldProfile,
upsertRpgWorldProfile,
} from './rpgCreationLibraryClient';
export {
buildRpgCreationPreviewFromAgentDraft,
rpgCreationPreviewAdapter,
} from './rpgCreationPreviewAdapter';
export { listRpgCreationWorks, rpgCreationWorkClient } from './rpgCreationWorkClient';

View File

@@ -0,0 +1,33 @@
import {
createCustomWorldAgentSession,
executeCustomWorldAgentAction,
getCustomWorldAgentCardDetail,
getCustomWorldAgentOperation,
getCustomWorldAgentSession,
sendCustomWorldAgentMessage,
streamCustomWorldAgentMessage,
} from '../aiService';
/**
* 工作包 A 先把 RPG 创作 Agent 请求聚合到独立 client 命名空间。
* 当前仍直接透传旧实现,后续工作包 D 再逐步把 `aiService.ts` 中的相关接口迁出。
*/
export const rpgCreationAgentClient = {
createSession: createCustomWorldAgentSession,
getSession: getCustomWorldAgentSession,
sendMessage: sendCustomWorldAgentMessage,
streamMessage: streamCustomWorldAgentMessage,
executeAction: executeCustomWorldAgentAction,
getOperation: getCustomWorldAgentOperation,
getCardDetail: getCustomWorldAgentCardDetail,
};
export {
createCustomWorldAgentSession as createRpgCreationSession,
executeCustomWorldAgentAction as executeRpgCreationAction,
getCustomWorldAgentCardDetail as getRpgCreationCardDetail,
getCustomWorldAgentOperation as getRpgCreationOperation,
getCustomWorldAgentSession as getRpgCreationSession,
sendCustomWorldAgentMessage as sendRpgCreationMessage,
streamCustomWorldAgentMessage as streamRpgCreationMessage,
};

View File

@@ -0,0 +1,35 @@
import {
generateCustomWorldLandmark,
generateCustomWorldPlayableNpc,
generateCustomWorldSceneImage,
generateCustomWorldSceneNpc,
generateCustomWorldStoryNpc,
} from '../aiService';
import {
generateCustomWorldCoverImage,
uploadCustomWorldCoverImage,
} from '../customWorldCoverAssetService';
/**
* 工作包 A 先把 RPG 创作资产相关请求收口到独立 client。
* 当前仍桥接旧接口,后续工作包 C、D 会继续细分角色资产、场景资产和封面资产职责。
*/
export const rpgCreationAssetClient = {
generateSceneImage: generateCustomWorldSceneImage,
generateSceneNpc: generateCustomWorldSceneNpc,
generatePlayableNpc: generateCustomWorldPlayableNpc,
generateStoryNpc: generateCustomWorldStoryNpc,
generateLandmark: generateCustomWorldLandmark,
generateCoverImage: generateCustomWorldCoverImage,
uploadCoverImage: uploadCustomWorldCoverImage,
};
export {
generateCustomWorldCoverImage as generateRpgWorldCoverImage,
generateCustomWorldLandmark as generateRpgWorldLandmark,
generateCustomWorldPlayableNpc as generateRpgWorldPlayableNpc,
generateCustomWorldSceneImage as generateRpgWorldSceneImage,
generateCustomWorldSceneNpc as generateRpgWorldSceneNpc,
generateCustomWorldStoryNpc as generateRpgWorldStoryNpc,
uploadCustomWorldCoverImage as uploadRpgWorldCoverImage,
};

View File

@@ -0,0 +1,33 @@
import {
deleteCustomWorldProfile,
getCustomWorldGalleryDetail,
listCustomWorldGallery,
listCustomWorldLibrary,
publishCustomWorldProfile,
unpublishCustomWorldProfile,
upsertCustomWorldProfile,
} from '../storageService';
/**
* 工作包 A 先建立 RPG 世界作品库和广场相关请求的统一入口。
* 当前实现仍透传旧 `storageService.ts`,后续工作包 D 会把作品链路彻底迁入这里。
*/
export const rpgCreationLibraryClient = {
listLibrary: listCustomWorldLibrary,
upsertProfile: upsertCustomWorldProfile,
deleteProfile: deleteCustomWorldProfile,
publishProfile: publishCustomWorldProfile,
unpublishProfile: unpublishCustomWorldProfile,
listGallery: listCustomWorldGallery,
getGalleryDetail: getCustomWorldGalleryDetail,
};
export {
deleteCustomWorldProfile as deleteRpgWorldProfile,
getCustomWorldGalleryDetail as getRpgWorldGalleryDetail,
listCustomWorldGallery as listRpgWorldGallery,
listCustomWorldLibrary as listRpgWorldLibrary,
publishCustomWorldProfile as publishRpgWorldProfile,
unpublishCustomWorldProfile as unpublishRpgWorldProfile,
upsertCustomWorldProfile as upsertRpgWorldProfile,
};

View File

@@ -0,0 +1,13 @@
import { buildCustomWorldProfileFromAgentDraft } from '../customWorldAgentDraftResult';
/**
* 这是工作包 A 提供的新命名兼容层。
* 当前仍复用旧的前端草稿编译逻辑,后续 Phase 3 会继续把结果预览编译后移到服务端。
*/
export const rpgCreationPreviewAdapter = {
buildPreviewFromAgentDraft: buildCustomWorldProfileFromAgentDraft,
};
export {
buildCustomWorldProfileFromAgentDraft as buildRpgCreationPreviewFromAgentDraft,
};

View File

@@ -0,0 +1,11 @@
import { listCustomWorldWorks } from '../storageService';
/**
* 工作包 A 先建立 RPG 创作作品流的独立 client。
* 当前作品列表仍复用旧存储服务,后续工作包 D 再切出真正的专属请求实现。
*/
export const rpgCreationWorkClient = {
listWorks: listCustomWorldWorks,
};
export { listCustomWorldWorks as listRpgCreationWorks };