feat: complete TASK-WP2-02 project autosave

This commit is contained in:
suyx
2026-08-02 18:28:07 +08:00
parent 4d38530361
commit da6fa25e60
17 changed files with 2268 additions and 35 deletions
+10 -1
View File
@@ -1,6 +1,6 @@
// Generated from openapi/openapi.json. Do not edit by hand.
import type { AccountDeletionResponse, AccountDeletionCompleteRequest, AdminLoginCompleteResponse, AdminLoginCompleteRequest, LoginCompleteResponse, LoginCompleteRequest, RegistrationCompleteResponse, RegistrationCompleteRequest, AccountSettingsResponse, AdminSessionResponse, ProjectDetailResponse, UserSessionResponse, ProjectListResponse, LogoutResponse, ProjectRenameResponse, ProjectRenameRequest, AccountDeletionSendResponse, RegistrationSendResponse, AdminLoginSendRequest, LoginSendRequest, RegistrationSendRequest, FailedEmptyTrashResponse, FailedEmptyTrashRequest, AccountProfileUpdateResponse, AccountProfileUpdateRequest } from "./types.gen.js";
import type { AccountDeletionResponse, AccountDeletionCompleteRequest, AdminLoginCompleteResponse, AdminLoginCompleteRequest, LoginCompleteResponse, LoginCompleteRequest, RegistrationCompleteResponse, RegistrationCompleteRequest, AccountSettingsResponse, AdminSessionResponse, ProjectDetailResponse, UserSessionResponse, ProjectListResponse, LogoutResponse, ProjectRenameResponse, ProjectRenameRequest, ProjectStateSaveResponse, ProjectEditableState, AccountDeletionSendResponse, RegistrationSendResponse, AdminLoginSendRequest, LoginSendRequest, RegistrationSendRequest, FailedEmptyTrashResponse, FailedEmptyTrashRequest, AccountProfileUpdateResponse, AccountProfileUpdateRequest } from "./types.gen.js";
export interface ClientOptions { baseUrl?: string; fetch?: typeof globalThis.fetch; headers?: HeadersInit; }
@@ -175,6 +175,15 @@ export async function renameProject(body: ProjectRenameRequest, options: ClientO
return response.json() as Promise<ProjectRenameResponse>;
}
export async function saveProjectState(body: ProjectEditableState, options: ClientOptions = {}): Promise<ProjectStateSaveResponse> {
const request = options.fetch ?? globalThis.fetch;
const headers = new Headers(options.headers);
headers.set("Content-Type", "application/json");
const response = await request(`${options.baseUrl ?? ""}/api/v1/projects/{projectId}/state`, { body: JSON.stringify(body), method: "PUT", headers });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json() as Promise<ProjectStateSaveResponse>;
}
export async function sendAccountDeletionCode(options: ClientOptions = {}): Promise<AccountDeletionSendResponse> {
const request = options.fetch ?? globalThis.fetch;
const response = await request(`${options.baseUrl ?? ""}/api/v1/account/deletion/send`, { method: "POST", headers: options.headers ?? {} });
+82
View File
@@ -136,6 +136,65 @@ export type BrowserSupportSuccess = {
export type BrowserUnsupportedReason = "platform_unsupported" | "brand_unsupported" | "version_unsupported" | "identity_unavailable";
export type CanvasBackgroundAdjustments = {
"brightness": number;
"contrast": number;
"crop": {
"height": number;
"width": number;
"x": number;
"y": number;
} | null;
"filter": string;
"fit": "fill" | "fit" | "crop";
"saturation": number;
"sharpness": number;
"temperature": number;
};
export type CanvasElement = {
"colors"?: Array<string>;
"content"?: string;
"coordinates"?: {
"latitude": number;
"longitude": number;
};
"created_at": string;
"dynamic_fields"?: Record<string, never>;
"element_id": string;
"font_override"?: string;
"font_size"?: number;
"formatted_value"?: string;
"opacity": number;
"position": {
"x": number;
"y": number;
};
"resource_version": string;
"rotation": number;
"scale": {
"x": number;
"y": number;
};
"style_id"?: string;
"style_parameters"?: Record<string, never>;
"template_or_asset_id": string;
"type": "text_template" | "static_sticker" | "color_card" | "dynamic_sticker";
"z_index": number;
};
export type CanvasState = {
"background": {
"adjustments": CanvasBackgroundAdjustments;
"asset_id": string | null;
};
"elements": Array<CanvasElement>;
"pixel_height": number;
"pixel_width": number;
"ratio": "3:4" | "1:1" | "4:3" | "9:16";
"schema_version": 1;
};
export type CorrelationId = string;
export type CreditSummary = {
@@ -251,6 +310,7 @@ export type ModelRuntimeSseEvent = {
};
export type ProjectDetailResponse = {
"canvas_state": CanvasState;
"created_at": string;
"current_image_id": ProjectId | null;
"deleted_at": string | null;
@@ -263,12 +323,18 @@ export type ProjectDetailResponse = {
"project_id": ProjectId;
"purge_at": string | null;
"ratio": ProjectRatio;
"save_status": "saved";
"state_version": number;
"status": ProjectViewStatus;
"successful_image_count": number;
"updated_at": string;
};
export type ProjectEditableState = {
"canvas_state": CanvasState;
"name": string;
};
export type ProjectId = string;
export type ProjectImageItem = {
@@ -303,6 +369,22 @@ export type ProjectRenameResponse = {
"status": "renamed";
};
export type ProjectStateConflictResponse = {
"latest_state_version": number;
"save_status": "conflicted";
};
export type ProjectStateSaveHeaders = {
"idempotency-key": string;
"if-match": string;
"x-csrf-token": string;
};
export type ProjectStateSaveResponse = {
"save_status": "saved";
"state_version": number;
};
export type ProjectSummary = {
"current_image_id": ProjectId | null;
"deleted_at": string | null;