fix(chat): sync paid voice audio unlock flow
This commit is contained in:
@@ -13,10 +13,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
creditsCharged: 10,
|
||||
requiredCredits: 10,
|
||||
shortfallCredits: 0,
|
||||
lockDetail: {
|
||||
locked: false,
|
||||
reason: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.unlocked).toBe(true);
|
||||
@@ -27,7 +23,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
expect(response.creditsCharged).toBe(10);
|
||||
expect(response.requiredCredits).toBe(10);
|
||||
expect(response.shortfallCredits).toBe(0);
|
||||
expect(response.lockDetail.locked).toBe(false);
|
||||
});
|
||||
|
||||
it("normalizes backend ids, audio aliases, and unlocked images", () => {
|
||||
@@ -43,10 +38,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
type: "promotion",
|
||||
url: "https://example.com/image.jpg",
|
||||
},
|
||||
lockDetail: {
|
||||
locked: false,
|
||||
reason: null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.messageId).toBe("backend-message-1");
|
||||
@@ -66,10 +57,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
creditsCharged: 0,
|
||||
requiredCredits: 10,
|
||||
shortfallCredits: 5,
|
||||
lockDetail: {
|
||||
locked: true,
|
||||
reason: "voice_message",
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.unlocked).toBe(false);
|
||||
@@ -78,10 +65,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
expect(response.creditsCharged).toBe(0);
|
||||
expect(response.requiredCredits).toBe(10);
|
||||
expect(response.shortfallCredits).toBe(5);
|
||||
expect(response.lockDetail).toEqual({
|
||||
locked: true,
|
||||
reason: "voice_message",
|
||||
});
|
||||
});
|
||||
|
||||
it("defaults nullable content to an empty string", () => {
|
||||
@@ -90,10 +73,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
content: null,
|
||||
audioUrl: null,
|
||||
reason: "insufficient_balance",
|
||||
lockDetail: {
|
||||
locked: true,
|
||||
reason: "private_message",
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.content).toBe("");
|
||||
@@ -109,10 +88,6 @@ describe("UnlockPrivateResponse", () => {
|
||||
creditsCharged: null,
|
||||
requiredCredits: null,
|
||||
shortfallCredits: null,
|
||||
lockDetail: {
|
||||
locked: true,
|
||||
reason: "image_paywall",
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.creditBalance).toBe(0);
|
||||
@@ -121,21 +96,7 @@ describe("UnlockPrivateResponse", () => {
|
||||
expect(response.shortfallCredits).toBe(0);
|
||||
});
|
||||
|
||||
it("defaults nullable lock detail through schema helpers", () => {
|
||||
const response = UnlockPrivateResponse.from({
|
||||
unlocked: false,
|
||||
content: "",
|
||||
reason: "insufficient_balance",
|
||||
lockDetail: null,
|
||||
});
|
||||
|
||||
expect(response.lockDetail).toEqual({
|
||||
locked: false,
|
||||
reason: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("strips legacy lock detail fields while preserving lock state and type", () => {
|
||||
it("strips legacy lock detail fields", () => {
|
||||
const response = UnlockPrivateResponse.fromJson({
|
||||
unlocked: false,
|
||||
lockDetail: {
|
||||
@@ -148,9 +109,7 @@ describe("UnlockPrivateResponse", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.lockDetail).toEqual({
|
||||
locked: true,
|
||||
reason: "private_message",
|
||||
});
|
||||
expect(response.toJson()).not.toHaveProperty("lockDetail");
|
||||
expect(response).not.toHaveProperty("lockDetail");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
type UnlockPrivateResponseData,
|
||||
type UnlockPrivateResponseInput,
|
||||
} from "@/data/schemas/chat/response/unlock_private_response";
|
||||
import type { ChatLockDetailData } from "@/data/schemas/chat";
|
||||
import type { ChatImageData, ChatLockType } from "@/data/schemas/chat";
|
||||
|
||||
/**
|
||||
@@ -23,7 +22,6 @@ export class UnlockPrivateResponse {
|
||||
declare readonly creditsCharged: number;
|
||||
declare readonly requiredCredits: number;
|
||||
declare readonly shortfallCredits: number;
|
||||
declare readonly lockDetail: ChatLockDetailData;
|
||||
|
||||
private constructor(input: UnlockPrivateResponseInput) {
|
||||
const data = UnlockPrivateResponseSchema.parse(input);
|
||||
|
||||
@@ -34,7 +34,6 @@ function makeResponse(
|
||||
): ChatSendResponse {
|
||||
return ChatSendResponse.from({
|
||||
reply: "",
|
||||
audioUrl: "",
|
||||
messageId: "msg-1",
|
||||
isGuest: false,
|
||||
timestamp: 1782356425363,
|
||||
@@ -92,6 +91,33 @@ describe("chat media cache helpers", () => {
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not cache audio from a locked send response", () => {
|
||||
expect(
|
||||
getSendResponseMediaTargets(
|
||||
makeResponse({
|
||||
audioUrl: "https://example.com/locked.mp3",
|
||||
lockDetail: { locked: true, reason: "voice_message" },
|
||||
}),
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("caches audio from an unlocked send response", () => {
|
||||
expect(
|
||||
getSendResponseMediaTargets(
|
||||
makeResponse({
|
||||
audioUrl: "https://example.com/unlocked.mp3",
|
||||
}),
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
messageId: "msg-1",
|
||||
kind: "audio",
|
||||
remoteUrl: "https://example.com/unlocked.mp3",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("deduplicates media targets", () => {
|
||||
expect(
|
||||
uniqueMediaTargets([
|
||||
|
||||
@@ -42,11 +42,13 @@ export function getSendResponseMediaTargets(
|
||||
kind: "image",
|
||||
remoteUrl: response.image.url,
|
||||
});
|
||||
pushMediaTarget(targets, {
|
||||
messageId: response.messageId,
|
||||
kind: "audio",
|
||||
remoteUrl: response.audioUrl,
|
||||
});
|
||||
if (!response.lockDetail.locked) {
|
||||
pushMediaTarget(targets, {
|
||||
messageId: response.messageId,
|
||||
kind: "audio",
|
||||
remoteUrl: response.audioUrl,
|
||||
});
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
stringOrEmpty,
|
||||
stringOrNull,
|
||||
} from "../../nullable-defaults";
|
||||
import { ChatImageSchema, ChatLockDetailSchema } from "../chat_payloads";
|
||||
import { ChatImageSchema } from "../chat_payloads";
|
||||
import { ChatLockTypeSchema } from "../chat_lock_type";
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,6 @@ export const UnlockPrivateResponseSchema = z
|
||||
creditsCharged: numberOrZero,
|
||||
requiredCredits: numberOrZero,
|
||||
shortfallCredits: numberOrZero,
|
||||
lockDetail: ChatLockDetailSchema,
|
||||
})
|
||||
.transform(({ reply, message_id, audio_url, ...data }) => ({
|
||||
...data,
|
||||
|
||||
Reference in New Issue
Block a user