feat(chat): add support action cards and live entitlements
Docker Image / Build and Push Docker Image (push) Successful in 2m2s
Docker Image / Build and Push Docker Image (push) Successful in 2m2s
This commit is contained in:
@@ -60,6 +60,26 @@ describe("multi-character API contract", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an idempotent chat action event", async () => {
|
||||
const body = {
|
||||
eventId: "4b223884-02ec-4fd2-aacf-e84ee8ca3adb",
|
||||
actionId: "action-1",
|
||||
characterId: CHARACTER_ID,
|
||||
eventType: "opened" as const,
|
||||
};
|
||||
httpClientMock.mockResolvedValue({
|
||||
success: true,
|
||||
data: { ...body, duplicate: false },
|
||||
});
|
||||
|
||||
await new ChatApi().recordActionEvent(body);
|
||||
|
||||
expect(httpClientMock).toHaveBeenCalledWith("/api/chat/action-events", {
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
});
|
||||
|
||||
it("persists the character opening message with the canonical contract", async () => {
|
||||
httpClientMock.mockResolvedValue({
|
||||
success: true,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"paymentTipMessage": { "method": "post", "path": "/api/payment/tip-message" },
|
||||
"paymentCommercialOfferAccept": { "method": "post", "path": "/api/payment/commercial-offers/{offerId}/accept" },
|
||||
"chatSend": { "method": "post", "path": "/api/chat/send" },
|
||||
"chatActionEvents": { "method": "post", "path": "/api/chat/action-events" },
|
||||
"chatOpeningMessage": { "method": "post", "path": "/api/chat/opening-message" },
|
||||
"chatHistory": { "method": "get", "path": "/api/chat/history" },
|
||||
"chatUnlockPrivate": { "method": "post", "path": "/api/chat/unlock-private" },
|
||||
|
||||
@@ -78,6 +78,9 @@ export class ApiPath {
|
||||
/** 发送消息 */
|
||||
static readonly chatSend = apiContract.chatSend.path;
|
||||
|
||||
/** 记录角色聊天操作卡漏斗事件 */
|
||||
static readonly chatActionEvents = apiContract.chatActionEvents.path;
|
||||
|
||||
/** 幂等保存角色开场白 */
|
||||
static readonly chatOpeningMessage = apiContract.chatOpeningMessage.path;
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ import {
|
||||
ChatPreviewsResponseSchema,
|
||||
ChatSendResponse,
|
||||
ChatSendResponseSchema,
|
||||
ChatActionEventRequest,
|
||||
ChatActionEventRequestSchema,
|
||||
ChatActionEventResponse,
|
||||
ChatActionEventResponseSchema,
|
||||
OpeningMessageRequest,
|
||||
OpeningMessageResponse,
|
||||
OpeningMessageResponseSchema,
|
||||
@@ -42,6 +46,21 @@ export class ChatApi {
|
||||
return ChatSendResponseSchema.parse(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/** 上报白名单聊天操作卡事件;eventId 用于安全重试。 */
|
||||
async recordActionEvent(
|
||||
body: ChatActionEventRequest,
|
||||
): Promise<ChatActionEventResponse> {
|
||||
const request = ChatActionEventRequestSchema.parse(body);
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.chatActionEvents,
|
||||
{
|
||||
method: "POST",
|
||||
body: request,
|
||||
},
|
||||
);
|
||||
return ChatActionEventResponseSchema.parse(unwrap(env));
|
||||
}
|
||||
|
||||
/** 幂等保存当前角色的首次开场白。 */
|
||||
async saveOpeningMessage(
|
||||
body: OpeningMessageRequest,
|
||||
|
||||
Reference in New Issue
Block a user