refactor(private-zone): use canonical product name
Docker Image / Build and Push Docker Image (push) Successful in 2m7s

This commit is contained in:
Codex
2026-07-23 10:53:41 +08:00
parent 30122a44db
commit 0357fbcaff
105 changed files with 578 additions and 578 deletions
@@ -71,7 +71,7 @@ describe("local character catalog", () => {
expect(snapshot.catalog.getById("maya-tan")).toMatchObject({
displayName: "Maya Backend",
assets: { avatar: "/images/avatar/maya.png" },
capabilities: { chat: true, privateZoom: false, tip: true },
capabilities: { chat: true, privateZone: false, tip: true },
});
expect(snapshot.defaultCharacter.id).toBe("elio");
});
@@ -101,7 +101,7 @@ describe("local character catalog", () => {
for (const character of CHARACTERS) {
expect(character.capabilities).toEqual({
chat: true,
privateZoom: true,
privateZone: true,
tip: true,
});
expect(character.tagline.length).toBeGreaterThan(0);
+18 -18
View File
@@ -1,6 +1,6 @@
export interface CharacterCapabilities {
readonly chat: boolean;
readonly privateZoom: boolean;
readonly privateZone: boolean;
readonly tip: boolean;
}
@@ -17,12 +17,12 @@ export interface CharacterProfile {
readonly avatar: string;
readonly cover: string;
readonly chatBackground: string;
readonly privateZoomBanner: string;
readonly privateZoneBanner: string;
};
readonly copy: {
readonly splashRelationship: string;
readonly privateZoomTitle: string;
readonly privateZoomSubtitle: string;
readonly privateZoneTitle: string;
readonly privateZoneSubtitle: string;
readonly tipHeader: string;
readonly tipTitle: string;
};
@@ -62,19 +62,19 @@ const CHARACTER_PROFILES: readonly CharacterProfile[] = Object.freeze([
"Finally I can relax. How was your day out?",
capabilities: {
chat: true,
privateZoom: true,
privateZone: true,
tip: true,
},
assets: {
avatar: "/images/avatar/elio.png",
cover: "/images/cover/elio.png",
chatBackground: "/images/chat/bg-chatpage.png",
privateZoomBanner: "/images/private-zoom/banner/elio.png",
privateZoneBanner: "/images/private-zone/banner/elio.png",
},
copy: {
splashRelationship: "Your exclusive AI boyfriend",
privateZoomTitle: "Elio Private Zoom",
privateZoomSubtitle: "Join me, unlock my private zoom",
privateZoneTitle: "Elio Private Zone",
privateZoneSubtitle: "Join me, unlock my private zone",
tipHeader: "Tip Elio",
tipTitle: "Buy Elio a coffee",
},
@@ -91,19 +91,19 @@ const CHARACTER_PROFILES: readonly CharacterProfile[] = Object.freeze([
"How was your day?",
capabilities: {
chat: true,
privateZoom: true,
privateZone: true,
tip: true,
},
assets: {
avatar: "/images/avatar/maya.png",
cover: "/images/cover/maya.webp",
chatBackground: "/images/chat/bg-chatpage.png",
privateZoomBanner: "/images/private-zoom/banner/maya.png",
privateZoneBanner: "/images/private-zone/banner/maya.png",
},
copy: {
splashRelationship: "Your exclusive AI girlfriend",
privateZoomTitle: "Maya Private Zoom",
privateZoomSubtitle: "Join me, unlock my private zoom",
privateZoneTitle: "Maya Private Zone",
privateZoneSubtitle: "Join me, unlock my private zone",
tipHeader: "Tip Maya",
tipTitle: "Buy Maya a coffee",
},
@@ -120,19 +120,19 @@ const CHARACTER_PROFILES: readonly CharacterProfile[] = Object.freeze([
"Tell me how your day went.",
capabilities: {
chat: true,
privateZoom: true,
privateZone: true,
tip: true,
},
assets: {
avatar: "/images/avatar/nayeli.png",
cover: "/images/cover/nayeli.webp",
chatBackground: "/images/chat/bg-chatpage.png",
privateZoomBanner: "/images/private-zoom/banner/nayeli.png",
privateZoneBanner: "/images/private-zone/banner/nayeli.png",
},
copy: {
splashRelationship: "Your exclusive AI girlfriend",
privateZoomTitle: "Nayeli Private Zoom",
privateZoomSubtitle: "Join me, unlock my private zoom",
privateZoneTitle: "Nayeli Private Zone",
privateZoneSubtitle: "Join me, unlock my private zone",
tipHeader: "Tip Nayeli",
tipTitle: "Buy Nayeli a coffee",
},
@@ -186,8 +186,8 @@ export function mergeRemoteCharacterCatalog(
sortOrder: item.sortOrder,
capabilities: {
chat: item.capabilities.chat,
privateZoom:
local.capabilities.privateZoom && item.capabilities.privateContent,
privateZone:
local.capabilities.privateZone && item.capabilities.privateContent,
tip: local.capabilities.tip,
},
}),
+2 -2
View File
@@ -8,7 +8,7 @@ export * from "./character_repository";
export * from "./feedback_repository";
export * from "./metrics_repository";
export * from "./payment_repository";
export * from "./private_zoom_repository";
export * from "./private_zone_repository";
export * from "./user_repository";
export * from "./interfaces/iauth_repository";
export * from "./interfaces/ichat_repository";
@@ -16,5 +16,5 @@ export * from "./interfaces/icharacter_repository";
export * from "./interfaces/ifeedback_repository";
export * from "./interfaces/imetrics_repository";
export * from "./interfaces/ipayment_repository";
export * from "./interfaces/iprivate_zoom_repository";
export * from "./interfaces/iprivate_zone_repository";
export * from "./interfaces/iuser_repository";
+1 -1
View File
@@ -8,5 +8,5 @@ export * from "./icharacter_repository";
export * from "./ifeedback_repository";
export * from "./imetrics_repository";
export * from "./ipayment_repository";
export * from "./iprivate_zoom_repository";
export * from "./iprivate_zone_repository";
export * from "./iuser_repository";
@@ -1,7 +1,7 @@
import type {
PrivateAlbumsResponse,
PrivateAlbumUnlockResponse,
} from "@/data/schemas/private-zoom";
} from "@/data/schemas/private-zone";
import type { Result } from "@/utils/result";
export interface GetPrivateAlbumsInput {
@@ -9,7 +9,7 @@ export interface GetPrivateAlbumsInput {
limit?: number;
}
export interface IPrivateZoomRepository {
export interface IPrivateZoneRepository {
getAlbums(
input: GetPrivateAlbumsInput,
): Promise<Result<PrivateAlbumsResponse>>;
@@ -1,22 +1,22 @@
import type {
GetPrivateAlbumsInput,
IPrivateZoomRepository,
IPrivateZoneRepository,
} from "@/data/repositories/interfaces";
import {
type PrivateAlbumsResponse,
type PrivateAlbumUnlockResponse,
UnlockPrivateAlbumRequestSchema,
} from "@/data/schemas/private-zoom";
} from "@/data/schemas/private-zone";
import {
PrivateZoomApi,
privateZoomApi,
} from "@/data/services/api/private_zoom_api";
PrivateZoneApi,
privateZoneApi,
} from "@/data/services/api/private_zone_api";
import { Result } from "@/utils/result";
import { createLazySingleton } from "./lazy_singleton";
export class PrivateZoomRepository implements IPrivateZoomRepository {
constructor(private readonly api: PrivateZoomApi) {}
export class PrivateZoneRepository implements IPrivateZoneRepository {
constructor(private readonly api: PrivateZoneApi) {}
getAlbums(
input: GetPrivateAlbumsInput,
@@ -37,7 +37,7 @@ export class PrivateZoomRepository implements IPrivateZoomRepository {
}
}
export const getPrivateZoomRepository =
createLazySingleton<IPrivateZoomRepository>(
() => new PrivateZoomRepository(privateZoomApi),
export const getPrivateZoneRepository =
createLazySingleton<IPrivateZoneRepository>(
() => new PrivateZoneRepository(privateZoneApi),
);
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
import { FacebookIdentityResponseSchema } from "@/data/schemas/auth";
import { ChatHistoryResponseSchema } from "@/data/schemas/chat";
import { PaymentPlansResponseSchema } from "@/data/schemas/payment";
import { PrivateAlbumsResponseSchema } from "@/data/schemas/private-zoom";
import { PrivateAlbumsResponseSchema } from "@/data/schemas/private-zone";
import { UserSchema } from "@/data/schemas/user";
describe("immutable schemas", () => {
@@ -33,7 +33,7 @@ describe("immutable schemas", () => {
expectDeepFrozen(response);
});
it("freezes payment and private-zoom collections", () => {
it("freezes payment and private-zone collections", () => {
const plans = PaymentPlansResponseSchema.parse({
firstRechargeOffer: {
enabled: true,
@@ -4,7 +4,7 @@ import {
PrivateAlbumUnlockResponseSchema,
PrivateAlbumsResponseSchema,
UnlockPrivateAlbumRequestSchema,
} from "@/data/schemas/private-zoom";
} from "@/data/schemas/private-zone";
import { ApiPath } from "@/data/services/api";
const ALBUM_ID = "a1b2c3d4-0000-0000-0000-000000000000";
@@ -96,8 +96,8 @@ describe("Private Album schema models", () => {
});
it("encodes the album id in the unlock path", () => {
expect(ApiPath.privateZoomAlbumUnlock("album:91")).toBe(
"/api/private-zoom/albums/album%3A91/unlock",
expect(ApiPath.privateZoneAlbumUnlock("album:91")).toBe(
"/api/private-zone/albums/album%3A91/unlock",
);
});
});
@@ -6,7 +6,7 @@ import { ApiPath } from "../api_path";
describe("ApiPath contract source", () => {
it("uses the shared contract path for every static operation", () => {
const staticOperations = Object.entries(apiContract).filter(
([operationId]) => operationId !== "privateZoomAlbumUnlock",
([operationId]) => operationId !== "privateZoneAlbumUnlock",
);
for (const [operationId, operation] of staticOperations) {
@@ -17,8 +17,8 @@ describe("ApiPath contract source", () => {
});
it("fills and encodes the private album path parameter", () => {
expect(ApiPath.privateZoomAlbumUnlock("album/id 1")).toBe(
"/api/private-zoom/albums/album%2Fid%201/unlock",
expect(ApiPath.privateZoneAlbumUnlock("album/id 1")).toBe(
"/api/private-zone/albums/album%2Fid%201/unlock",
);
});
});
@@ -14,7 +14,7 @@ vi.mock("../http_client", () => ({
import { ChatApi } from "../chat_api";
import { CharacterApi } from "../character_api";
import { PrivateZoomApi } from "../private_zoom_api";
import { PrivateZoneApi } from "../private_zone_api";
const CHARACTER_ID = "elio";
@@ -146,18 +146,18 @@ describe("multi-character API contract", () => {
);
});
it("scopes private-zoom albums to characterId", async () => {
it("scopes private-zone albums to characterId", async () => {
httpClientMock.mockResolvedValue({
success: true,
data: { items: [], creditBalance: 0 },
});
await new PrivateZoomApi().getAlbums({
await new PrivateZoneApi().getAlbums({
characterId: CHARACTER_ID,
limit: 20,
});
expect(httpClientMock).toHaveBeenCalledWith("/api/private-zoom/albums", {
expect(httpClientMock).toHaveBeenCalledWith("/api/private-zone/albums", {
query: { characterId: CHARACTER_ID, limit: 20 },
});
});
+2 -2
View File
@@ -21,8 +21,8 @@
"chatHistory": { "method": "get", "path": "/api/chat/history" },
"chatUnlockPrivate": { "method": "post", "path": "/api/chat/unlock-private" },
"chatUnlockHistory": { "method": "post", "path": "/api/chat/unlock-history" },
"privateZoomAlbums": { "method": "get", "path": "/api/private-zoom/albums" },
"privateZoomAlbumUnlock": { "method": "post", "path": "/api/private-zoom/albums/{albumId}/unlock" },
"privateZoneAlbums": { "method": "get", "path": "/api/private-zone/albums" },
"privateZoneAlbumUnlock": { "method": "post", "path": "/api/private-zone/albums/{albumId}/unlock" },
"metricsPwaEvent": { "method": "post", "path": "/api/metrics/pwa/event" },
"reportUserInfo": { "method": "post", "path": "/api/data/report-user-info" },
"feedback": { "method": "post", "path": "/api/feedback" },
+3 -3
View File
@@ -81,11 +81,11 @@ export class ApiPath {
// ============ 私密空间相关 ============
/** 获取私密图片包列表 */
static readonly privateZoomAlbums = apiContract.privateZoomAlbums.path;
static readonly privateZoneAlbums = apiContract.privateZoneAlbums.path;
/** 解锁私密图片包 */
static privateZoomAlbumUnlock(albumId: string): string {
return apiContract.privateZoomAlbumUnlock.path.replace(
static privateZoneAlbumUnlock(albumId: string): string {
return apiContract.privateZoneAlbumUnlock.path.replace(
"{albumId}",
encodeURIComponent(albumId),
);
+1 -1
View File
@@ -12,6 +12,6 @@ export * from "./feedback_api";
export * from "./http_client";
export * from "./metrics_api";
export * from "./payment_api";
export * from "./private_zoom_api";
export * from "./private_zone_api";
export * from "./response_helper";
export * from "./user_api";
@@ -4,7 +4,7 @@ import {
PrivateAlbumUnlockResponse,
PrivateAlbumUnlockResponseSchema,
UnlockPrivateAlbumRequest,
} from "@/data/schemas/private-zoom";
} from "@/data/schemas/private-zone";
import { ApiPath } from "./api_path";
import { httpClient } from "./http_client";
@@ -15,12 +15,12 @@ export interface GetPrivateAlbumsInput {
limit?: number;
}
export class PrivateZoomApi {
export class PrivateZoneApi {
async getAlbums(
input: GetPrivateAlbumsInput,
): Promise<PrivateAlbumsResponse> {
const env = await httpClient<ApiEnvelope<unknown>>(
ApiPath.privateZoomAlbums,
ApiPath.privateZoneAlbums,
{
query: {
characterId: input.characterId,
@@ -36,7 +36,7 @@ export class PrivateZoomApi {
body: UnlockPrivateAlbumRequest,
): Promise<PrivateAlbumUnlockResponse> {
const env = await httpClient<ApiEnvelope<unknown>>(
ApiPath.privateZoomAlbumUnlock(albumId),
ApiPath.privateZoneAlbumUnlock(albumId),
{
method: "POST",
body,
@@ -46,4 +46,4 @@ export class PrivateZoomApi {
}
}
export const privateZoomApi = new PrivateZoomApi();
export const privateZoneApi = new PrivateZoneApi();
@@ -14,7 +14,7 @@ const PendingPaymentOrderSchema = z
subscriptionType: z.enum(["vip", "topup", "tip"]),
giftCategory: z.string().min(1).nullable().default(null),
giftPlanId: z.string().min(1).nullable().default(null),
returnTo: z.enum(["chat", "private-zoom", "profile"]).optional(),
returnTo: z.enum(["chat", "private-zone", "profile"]).optional(),
characterSlug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).optional(),
createdAt: z.number(),
})