feat(sdk): 根据API文档全面升级sdk-server.ts

- 完整实现Mixvideo Workflow API的所有接口
- 新增模板管理:创建、更新、删除、激活、禁用、同步Stripe等17个接口
- 新增支付处理:Stripe结账、成功/取消回调、退款、支付历史等8个接口
- 新增任务管理:创建任务、获取状态、进度追踪等3个接口
- 新增Google OAuth:登录、令牌刷新、用户信息、撤销等5个接口
- 完善TypeScript类型定义,新增15+个接口类型
- 优化中文注释和文档,添加emoji增强可读性
- 更新默认API基础URL为生产环境
- 改进错误处理和日志输出
- 保持向后兼容性

API支持:
- 模板管理 (Template Controller)
- 支付处理 (Payment Controller)
- 任务管理 (Task Controller)
- OAuth认证 (Auth Controller)
This commit is contained in:
imeepos
2025-09-26 22:46:47 +08:00
parent 142a38d7d1
commit 6c4247c8ea
2 changed files with 1606 additions and 77 deletions

956
API.md Normal file
View File

@@ -0,0 +1,956 @@
# Mixvideo Workflow API Documentation
## Overview
This document describes the REST API endpoints for the Mixvideo Workflow service, which provides video generation capabilities with Google OAuth integration, payment processing, and template management.
## Base URL
```
https://mixvideo-workflow.bowong.cc/
```
## Authentication
Most endpoints require authentication via OAuth tokens or API keys. Include tokens in the Authorization header:
```
Authorization: Bearer <access_token>
```
---
## Auth Controller (`/auth/google`)
### Google OAuth Authentication
#### `GET /auth/google/authorize`
Initiates Google OAuth authorization flow.
**Query Parameters:**
- `redirect_url` (optional): URL to redirect after authorization
- `scopes` (optional): Comma-separated OAuth scopes (default: openid,email,profile)
**Response:**
- Redirects to Google OAuth consent screen
---
#### `GET /auth/google/callback`
Handles OAuth callback from Google.
**Query Parameters:**
- `code`: Authorization code from Google
- `state`: State parameter for CSRF protection
- `error` (optional): Error code if authorization failed
**Success Response (200):**
```json
{
"success": true,
"code": 200,
"message": "OAuth authorization successful",
"data": {
"user": {
"id": "user_id",
"email": "user@example.com",
"name": "User Name"
},
"access_token": "ya29.xxx",
"expires_in": 3600
}
}
```
---
#### `POST /auth/google/refresh`
Refreshes OAuth access token.
**Request Body:**
```json
{
"refresh_token": "refresh_token_here",
"user_id": "optional_user_id"
}
```
**Response (200):**
```json
{
"success": true,
"code": 200,
"message": "Token refreshed successfully",
"data": {
"access_token": "new_access_token",
"expires_in": 3600,
"scope": "openid email profile"
}
}
```
---
#### `GET /auth/google/userinfo`
Retrieves user information from Google.
**Headers:**
- `Authorization: Bearer <access_token>` OR
- Query parameter: `access_token=<token>`
**Response (200):**
```json
{
"success": true,
"code": 200,
"message": "User info retrieved successfully",
"data": {
"id": "user_id",
"email": "user@example.com",
"name": "User Name",
"picture": "https://..."
}
}
```
---
#### `POST /auth/google/revoke`
Revokes OAuth token.
**Request Body:**
```json
{
"token": "token_to_revoke",
"user_id": "optional_user_id"
}
```
**Response (200):**
```json
{
"success": true,
"code": 200,
"message": "Token revoked successfully"
}
```
---
## Payment Controller (`/payment`)
### Stripe Payment Integration
#### `POST /payment/checkout/:templateCode`
Creates Stripe checkout session for a template.
**Path Parameters:**
- `templateCode`: Template identifier
**Request Body:**
```json
{
"userId": "user_123",
"metadata": {
"imageUrl": "https://example.com/image.jpg"
}
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Checkout session created successfully",
"data": {
"sessionId": "cs_xxx",
"url": "https://checkout.stripe.com/pay/cs_xxx",
"paymentId": "payment_123"
},
"timestamp": "2024-01-01T00:00:00Z",
"traceId": "trace_123"
}
```
---
#### `POST /payment/webhook`
Handles Stripe webhook events.
**Headers:**
- `stripe-signature`: Stripe webhook signature
**Request Body:** Raw webhook payload from Stripe
**Response (200):**
```json
{
"code": 200,
"message": "Webhook processed successfully"
}
```
---
#### `GET /payment/success`
Handles successful payment callback.
**Query Parameters:**
- `session_id`: Stripe session ID
- `payment_id`: Internal payment ID
**Response (200):**
```json
{
"code": 200,
"message": "Payment successful, template execution started",
"data": {
"payment": {
"id": "payment_123",
"status": "completed",
"templateCode": "template_001"
},
"execution": {
"executionId": "exec_123",
"taskId": "task_123"
}
}
}
```
---
#### `GET /payment/cancel`
Handles payment cancellation.
**Query Parameters:**
- `session_id`: Stripe session ID
- `payment_id`: Internal payment ID
**Response (200):**
```json
{
"code": 200,
"message": "Payment cancelled",
"data": {
"payment": {
"id": "payment_123",
"status": "cancelled"
}
}
}
```
---
#### `GET /payment/history`
Retrieves user payment history.
**Query Parameters:**
- `userId`: User identifier
**Response (200):**
```json
{
"code": 200,
"message": "Payment history retrieved successfully",
"data": {
"payments": [
{
"id": "payment_123",
"templateCode": "template_001",
"status": "completed",
"amount": 1000,
"currency": "usd",
"createdAt": "2024-01-01T00:00:00Z"
}
],
"total": 1
}
}
```
---
#### `POST /payment/refund/:paymentId`
Processes refund for a payment.
**Path Parameters:**
- `paymentId`: Payment identifier
**Request Body:**
```json
{
"reason": "user_request",
"amount": 1000,
"metadata": {
"note": "Customer requested refund"
}
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Refund processed successfully",
"data": {
"refundId": "re_xxx",
"amount": 1000,
"status": "succeeded"
}
}
```
---
#### `GET /payment/:paymentId`
Retrieves payment details.
**Path Parameters:**
- `paymentId`: Payment identifier
**Response (200):**
```json
{
"code": 200,
"message": "Payment details retrieved successfully",
"data": {
"id": "payment_123",
"templateCode": "template_001",
"userId": "user_123",
"status": "completed",
"amount": 1000,
"currency": "usd",
"stripeSessionId": "cs_xxx",
"executionId": "exec_123",
"createdAt": "2024-01-01T00:00:00Z"
}
}
```
---
#### `GET /payment/health`
Payment service health check.
**Response (200):**
```json
{
"code": 200,
"message": "Payment service is healthy",
"data": {
"timestamp": "2024-01-01T00:00:00Z",
"service": "PaymentController"
}
}
```
---
## Task Controller (`/task`)
### Task Management
#### `GET /task/:taskId`
Retrieves task status and details.
**Path Parameters:**
- `taskId`: Task identifier
**Response (200):**
```json
{
"code": 200,
"message": "Task status retrieved",
"data": {
"id": "task_123",
"status": "completed",
"progress": 100,
"result": {
"videoUrl": "https://example.com/output.mp4"
},
"createdAt": "2024-01-01T00:00:00Z",
"completedAt": "2024-01-01T00:05:00Z"
}
}
```
---
#### `POST /task`
Creates a new task.
**Request Body:**
```json
{
"type": "video_generation",
"templateCode": "template_001",
"userId": "user_123",
"parameters": {
"imageUrl": "https://example.com/input.jpg"
}
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Sent message to the queue",
"data": "task_123"
}
```
---
#### `POST /task/:taskId`
Creates task with specific ID.
**Path Parameters:**
- `taskId`: Desired task identifier
**Request Body:**
```json
{
"type": "video_generation",
"templateCode": "template_001",
"parameters": {
"imageUrl": "https://example.com/input.jpg"
}
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Sent message to the queue",
"data": "task_123"
}
```
---
## Template Controller (`/templates`)
### Template Management
#### `GET /templates`
Retrieves all active templates.
**Response (200):**
```json
{
"code": 200,
"message": "Templates retrieved successfully",
"data": {
"templates": [
{
"code": "template_001",
"name": "AI Video Generator",
"description": "Generate videos from images using AI",
"creditCost": 10,
"templateType": "VIDEO",
"isActive": true,
"tags": ["ai", "video", "generation"]
}
],
"total": 1
}
}
```
---
#### `GET /templates/get/:code`
Retrieves specific template by code.
**Path Parameters:**
- `code`: Template code
**Response (200):**
```json
{
"code": 200,
"message": "Template retrieved successfully",
"data": {
"code": "template_001",
"name": "AI Video Generator",
"description": "Generate videos from images using AI",
"creditCost": 10,
"templateType": "VIDEO",
"workflow": "video-generation-workflow",
"isActive": true,
"stripeProductId": "prod_xxx",
"createdAt": "2024-01-01T00:00:00Z"
}
}
```
---
#### `POST /templates`
Creates a new template.
**Request Body:**
```json
{
"code": "template_002",
"name": "New Template",
"description": "Template description",
"workflow": "workflow-name",
"creditCost": 15,
"version": "1.0.0",
"templateType": "IMAGE",
"tags": ["new", "template"],
"imageModel": "dall-e-3",
"imagePrompt": "Generate image based on: {prompt}"
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Template created successfully",
"data": {
"code": "template_002",
"stripeProductId": "prod_yyy",
"stripePriceId": "price_yyy"
}
}
```
---
#### `PUT /templates/update/:code`
Updates existing template.
**Path Parameters:**
- `code`: Template code
**Request Body:**
```json
{
"name": "Updated Template Name",
"description": "Updated description",
"creditCost": 20,
"isActive": true
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Template updated successfully",
"data": {
"updated": true,
"stripeSynced": true
}
}
```
---
#### `DELETE /templates/delete/:code`
Deletes template.
**Path Parameters:**
- `code`: Template code
**Response (200):**
```json
{
"code": 200,
"message": "Template deleted successfully",
"data": {
"deleted": true
}
}
```
---
#### `POST /templates/execute/:code`
Executes template workflow.
**Path Parameters:**
- `code`: Template code
**Request Body:**
```json
{
"userId": "user_123",
"imageUrl": "https://example.com/input.jpg"
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Template execution started",
"data": {
"executionId": "exec_123",
"taskId": "task_123",
"status": "running"
}
}
```
---
#### `POST /templates/activate/:code`
Activates template and syncs to Stripe.
**Path Parameters:**
- `code`: Template code
**Response (200):**
```json
{
"code": 200,
"message": "Template activated successfully",
"data": {
"isActive": true,
"stripeSynced": true
}
}
```
---
#### `POST /templates/deactivate/:code`
Deactivates template.
**Path Parameters:**
- `code`: Template code
**Response (200):**
```json
{
"code": 200,
"message": "Template deactivated successfully",
"data": {
"isActive": false,
"stripeSynced": true
}
}
```
---
#### `POST /templates/sync/:code`
Syncs template to Stripe.
**Path Parameters:**
- `code`: Template code
**Request Body (optional):**
```json
{
"forceUpdate": true
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Template sync completed",
"data": {
"synced": true,
"stripeProductId": "prod_xxx",
"stripePriceId": "price_xxx"
}
}
```
---
#### `GET /templates/execution/:taskId/progress`
Gets execution progress.
**Path Parameters:**
- `taskId`: Task identifier
**Response (200):**
```json
{
"code": 200,
"message": "Execution progress retrieved",
"data": {
"taskId": "task_123",
"executionId": "exec_123",
"status": "completed",
"progress": 100,
"result": {
"videoUrl": "https://example.com/output.mp4"
}
}
}
```
---
#### `GET /templates/executions/user/:userId`
Gets user execution history.
**Path Parameters:**
- `userId`: User identifier
**Response (200):**
```json
{
"code": 200,
"message": "User executions retrieved successfully",
"data": {
"executions": [
{
"executionId": "exec_123",
"templateCode": "template_001",
"status": "completed",
"createdAt": "2024-01-01T00:00:00Z"
}
],
"total": 1
}
}
```
---
#### `POST /templates/bulk`
Performs bulk operations on templates.
**Request Body:**
```json
{
"templateCodes": ["template_001", "template_002"],
"operation": "sync_stripe"
}
```
**Response (200):**
```json
{
"code": 200,
"message": "Bulk operation completed",
"data": {
"successful": ["template_001", "template_002"],
"failed": [],
"total": 2
}
}
```
---
#### `GET /templates/sync-all-stripe`
Syncs all templates to Stripe.
**Response (200):**
```json
{
"code": 200,
"message": "All templates synced to Stripe",
"data": {
"successful": 10,
"failed": 0,
"total": 10
}
}
```
---
#### `GET /templates/sync-status`
Checks template-Stripe sync status.
**Response (200):**
```json
{
"code": 200,
"message": "Sync status retrieved",
"data": {
"totalTemplates": 10,
"withStripeProduct": 8,
"activeTemplates": 9,
"needsSync": 1,
"templates": [
{
"code": "template_001",
"name": "Template Name",
"isActive": true,
"hasStripeProduct": true,
"lastStripeSyncAt": "2024-01-01T00:00:00Z"
}
]
}
}
```
---
#### `GET /templates/verify-sync/:code`
Verifies template Stripe sync status.
**Path Parameters:**
- `code`: Template code
**Response (200):**
```json
{
"code": 200,
"message": "Template sync verified successfully",
"data": {
"templateCode": "template_001",
"synced": true,
"issues": [],
"stripeProductId": "prod_xxx",
"stripePriceId": "price_xxx",
"recommendations": ["Template is properly synced with Stripe"]
}
}
```
---
#### `GET /templates/diagnose-stripe`
Diagnoses Stripe environment and configuration.
**Response (200):**
```json
{
"code": 200,
"message": "Stripe environment is healthy",
"data": {
"environment": "test",
"apiKeyValid": true,
"issues": [],
"accountInfo": {
"chargesEnabled": true,
"country": "US"
},
"recommendations": ["Stripe configuration appears healthy"]
}
}
```
---
#### `GET /templates/health`
Template service health check.
**Response (200):**
```json
{
"code": 200,
"message": "Template service is healthy",
"data": {
"totalTemplates": 10,
"timestamp": "2024-01-01T00:00:00Z",
"service": "TemplateService"
}
}
```
---
#### `GET /templates/init`
Initializes templates from JSON data.
**Response (200):**
```json
{
"code": 200,
"message": "Templates initialization completed",
"data": {
"total": 10,
"imported": 9,
"failed": 1,
"details": [
{
"code": "template_001",
"status": "success"
},
{
"code": "template_002",
"status": "error",
"error": "Template already exists"
}
]
}
}
```
---
#### `POST /templates/test/create`
Creates a test template for development.
**Response (200):**
```json
{
"code": 200,
"message": "Test template created successfully",
"data": {
"code": "test-image-generation",
"stripeProductId": "prod_test",
"stripePriceId": "price_test"
}
}
```
---
## Error Responses
All endpoints return standardized error responses:
**Error Response Format:**
```json
{
"code": 400,
"message": "Error description",
"timestamp": "2024-01-01T00:00:00Z",
"traceId": "trace_123"
}
```
**Common HTTP Status Codes:**
- `200` - Success
- `400` - Bad Request (validation errors, missing parameters)
- `401` - Unauthorized (missing or invalid authentication)
- `404` - Not Found (resource not found)
- `500` - Internal Server Error (server-side errors)
## Rate Limiting
API endpoints may be subject to rate limiting. Check response headers for rate limit information:
- `X-RateLimit-Limit`: Requests per time window
- `X-RateLimit-Remaining`: Remaining requests in current window
- `X-RateLimit-Reset`: Time when rate limit resets
## Data Types
### Template Types
- `IMAGE` - Image generation templates
- `VIDEO` - Video generation templates
### Payment Status
- `pending` - Payment initiated but not completed
- `completed` - Payment successfully processed
- `failed` - Payment failed
- `cancelled` - Payment cancelled by user
- `refunded` - Payment refunded
### Task Status
- `pending` - Task queued but not started
- `running` - Task currently executing
- `completed` - Task finished successfully
- `failed` - Task failed with error
### Refund Reasons
- `user_request` - User requested refund
- `technical_issue` - Technical problem occurred
- `duplicate` - Duplicate payment
- `fraudulent` - Fraudulent transaction

View File

@@ -3,67 +3,234 @@ import Taro from "@tarojs/taro"
import { IToken, IUser } from "./types";
import { createPlatformFactory } from "../platforms";
const TOKEN_STORAGE_KEY = 'access_token';
const TOKEN_UID_KEY = 'user_uid';
// ==================== 常量定义 ====================
const TOKEN_STORAGE_KEY = 'access_token'; // OAuth访问令牌存储键
const TOKEN_UID_KEY = 'user_uid'; // 用户ID存储键
/**
* 模板信息接口 - 匹配后端Template抽象类
*/
export interface Template {
code: string; // 模板唯一标识码
name: string; // 模板名称
description: string; // 模板详细描述
creditCost: number; // 积分消耗
version: string; // 版本号
inputExampleUrl: string; // 原始图片
outputExampleUrl: string; // 输出图片
tags: string[]; // 标签数组
templateType: string; // 模板类型
code: string; // 模板唯一标识码
name: string; // 模板名称
description: string; // 模板详细描述
creditCost: number; // 积分消耗
version?: string; // 版本号
inputExampleUrl?: string; // 原始图片示例
outputExampleUrl?: string; // 输出图片示例
tags: string[]; // 标签数组
templateType: 'IMAGE' | 'VIDEO'; // 模板类型:图片或视频
workflow?: string; // 工作流名称
isActive: boolean; // 是否激活
stripeProductId?: string; // Stripe产品ID
stripePriceId?: string; // Stripe价格ID
imageModel?: string; // 图片模型如dall-e-3
imagePrompt?: string; // 图片生成提示词
createdAt?: string; // 创建时间
lastStripeSyncAt?: string; // 最后同步Stripe时间
}
/**
* API 响应基础接口 - 匹配后端NestJS控制器的响应格式
*/
interface ApiResponse<T = any> {
status: boolean | string;
success: boolean | string;
code: number;
data: T;
msg: string;
success?: boolean; // 请求是否成功
code: number; // 状态码
message?: string; // 响应消息
msg?: string; // 兼容旧版本消息字段
data: T; // 响应数据
timestamp?: string; // 时间戳
traceId?: string; // 链路追踪ID
}
/**
* 模板执行参数
*/
export interface ExecuteTemplateParams {
templateCode: string;
imageUrl: string;
templateCode: string; // 模板代码
userId: string; // 用户ID
imageUrl: string; // 图片URL
}
/**
* 模板执行结果 - 后端返回字符串结果
* 模板执行结果
*/
export interface ExecuteTemplateResult {
result: string | null;
success: boolean;
message: string;
executionId: string; // 执行ID
taskId: string; // 任务ID
status: 'pending' | 'running' | 'completed' | 'failed'; // 任务状态
}
/**
* SDK服务端客户端
* 用于与后端模板服务进行通信
* 任务执行进度信息
*/
export interface TaskProgress {
taskId: string; // 任务ID
executionId: string; // 执行ID
status: 'pending' | 'running' | 'completed' | 'failed'; // 任务状态
progress: number; // 进度百分比 (0-100)
result?: {
videoUrl?: string; // 生成的视频URL
imageUrl?: string; // 生成的图片URL
};
createdAt: string; // 创建时间
completedAt?: string; // 完成时间
}
/**
* 支付会话创建参数
*/
export interface CreateCheckoutParams {
templateCode: string; // 模板代码
userId: string; // 用户ID
metadata: {
imageUrl: string; // 图片URL
[key: string]: any; // 其他元数据
};
}
/**
* 支付会话结果
*/
export interface CheckoutSessionResult {
sessionId: string; // Stripe会话ID
url: string; // 支付页面URL
paymentId: string; // 内部支付ID
}
/**
* 支付历史记录
*/
export interface PaymentHistory {
id: string; // 支付ID
templateCode: string; // 模板代码
status: 'pending' | 'completed' | 'failed' | 'cancelled' | 'refunded'; // 支付状态
amount: number; // 金额(分)
currency: string; // 货币类型
createdAt: string; // 创建时间
}
/**
* 退款参数
*/
export interface RefundParams {
reason: 'user_request' | 'technical_issue' | 'duplicate' | 'fraudulent'; // 退款原因
amount?: number; // 退款金额(分),不指定则全额退款
metadata?: {
note?: string; // 退款说明
[key: string]: any; // 其他元数据
};
}
/**
* Google OAuth用户信息
*/
export interface GoogleUserInfo {
id: string; // Google用户ID
email: string; // 邮箱
name: string; // 姓名
picture?: string; // 头像URL
}
/**
* OAuth令牌刷新参数
*/
export interface RefreshTokenParams {
refresh_token: string; // 刷新令牌
user_id?: string; // 用户ID可选
}
/**
* OAuth令牌响应
*/
export interface TokenResponse {
access_token: string; // 访问令牌
expires_in: number; // 过期时间(秒)
scope?: string; // 权限范围
refresh_token?: string; // 刷新令牌
}
/**
* 创建任务参数
*/
export interface CreateTaskParams {
type: 'video_generation' | 'image_generation'; // 任务类型
templateCode: string; // 模板代码
userId?: string; // 用户ID
parameters: {
imageUrl: string; // 图片URL
[key: string]: any; // 其他参数
};
}
/**
* 用户执行历史
*/
export interface UserExecution {
executionId: string; // 执行ID
templateCode: string; // 模板代码
status: 'pending' | 'running' | 'completed' | 'failed'; // 状态
createdAt: string; // 创建时间
result?: {
videoUrl?: string; // 生成的视频URL
imageUrl?: string; // 生成的图片URL
};
}
/**
* 批量操作参数
*/
export interface BulkOperationParams {
templateCodes: string[]; // 模板代码数组
operation: 'sync_stripe' | 'activate' | 'deactivate'; // 操作类型
}
/**
* 模板同步状态
*/
export interface TemplateSyncStatus {
code: string; // 模板代码
name: string; // 模板名称
isActive: boolean; // 是否激活
hasStripeProduct: boolean; // 是否有Stripe产品
lastStripeSyncAt?: string; // 最后同步时间
}
/**
* Mixvideo Workflow SDK客户端
* 用于与Mixvideo Workflow API进行通信支持
* - 模板管理(创建、更新、删除、激活、禁用)
* - 支付处理Stripe集成、结账、退款
* - 任务管理(视频生成、进度追踪)
* - Google OAuth认证登录、令牌刷新、撤销
*
* @example
* const sdk = new SdkServer('https://mixvideo-workflow.bowong.cc');
* const templates = await sdk.getAllTemplates();
*/
export class SdkServer {
private readonly baseUrl: string;
private readonly timeout: number;
private readonly baseUrl: string; // API基础URL
private readonly timeout: number; // 请求超时时间(毫秒)
constructor(url: string = `http://127.0.0.1:8787`, timeout: number = 5 * 60 * 1000) {
/**
* 初始化SDK客户端
* @param url API基础URL默认为Mixvideo Workflow的生产环境
* @param timeout 请求超时时间毫秒默认5分钟
*/
constructor(url: string = `https://mixvideo-workflow.bowong.cc`, timeout: number = 5 * 60 * 1000) {
this.baseUrl = url.endsWith('/') ? url.slice(0, -1) : url;
this.timeout = timeout;
}
/**
* 发送HTTP请求的通用方法
* 支持自动重试、错误处理、认证头部添加
* @param url 请求路径
* @param method HTTP方法
* @param data 请求数据
* @param retryCount 当前重试次数
* @returns API响应数据
*/
private async request<T>(
url: string,
@@ -75,7 +242,7 @@ export class SdkServer {
const retryDelay = 1000 * (retryCount + 1); // 递增延迟
try {
console.log(`SDK Server request: ${method} ${this.baseUrl}${url}`, { data, retryCount });
console.log(`🚀 SDK Server request: ${method} ${this.baseUrl}${url}`, { data, retryCount });
const requestConfig: any = {
url: `${this.baseUrl}${url}`,
@@ -112,7 +279,7 @@ export class SdkServer {
mode: `cors`
});
console.log(`SDK Server response:`, {
console.log(`SDK Server response:`, {
statusCode: response.statusCode,
data: response.data,
header: response.header
@@ -122,18 +289,15 @@ export class SdkServer {
const apiResponse = response.data as ApiResponse<T>;
// 检查API响应状态
if (apiResponse.success) {
if (apiResponse.success || apiResponse.code === 200) {
return apiResponse;
}
if (apiResponse.code === 200) {
return apiResponse
}
throw new Error(apiResponse.msg || 'API request failed');
throw new Error(apiResponse.message || apiResponse.msg || 'API request failed');
} else {
throw new Error(`HTTP ${response.statusCode}: ${response.data?.msg || 'Request failed'}`);
}
} catch (error: any) {
console.error('SDK Server request error:', {
console.error('SDK Server request error:', {
url: `${this.baseUrl}${url}`,
method,
data,
@@ -148,7 +312,7 @@ export class SdkServer {
error.errMsg?.includes('request:fail');
if (isNetworkError && retryCount < maxRetries) {
console.log(`Retrying request in ${retryDelay}ms... (${retryCount + 1}/${maxRetries})`);
console.log(`♾️ Retrying request in ${retryDelay}ms... (${retryCount + 1}/${maxRetries})`);
// 等待后重试
await new Promise(resolve => setTimeout(resolve, retryDelay));
@@ -158,26 +322,28 @@ export class SdkServer {
// 包装错误信息
const errorMessage = error.message || error.errMsg || 'Unknown network error';
throw new Error(`网络请求失败: ${errorMessage}`);
throw new Error(`😫 网络请求失败: ${errorMessage}`);
}
}
// ==================== 模板管理相关接口 ====================
/**
* 获取所有模板列表
* GET /
* 获取所有活跃模板列表
* GET /templates
*/
async getAllTemplates(): Promise<Template[]> {
const response = await this.request<{ templates: Template[] }>('/templates');
const response = await this.request<{ templates: Template[]; total: number }>('/templates');
return response.data.templates || [];
}
/**
* 根据模板代码获取单个模板信息
* GET /:templateCode
* GET /templates/get/:code
*/
async getTemplate(templateCode: string): Promise<Template | null> {
try {
const response = await this.request<Template | null>(`/templates/${templateCode}`);
const response = await this.request<Template>(`/templates/get/${templateCode}`);
return response.data;
} catch (error) {
console.warn(`Template ${templateCode} not found:`, error);
@@ -186,19 +352,200 @@ export class SdkServer {
}
/**
* 执行模板处理
* POST /
* 执行模板工作流
* POST /templates/execute/:code
*/
async executeTemplate(params: ExecuteTemplateParams): Promise<string | null> {
async executeTemplate(params: ExecuteTemplateParams): Promise<ExecuteTemplateResult> {
try {
const response = await this.request<string | any | null>(`/templates/code/${params.templateCode}/execute`, 'POST', {
imageUrl: params.imageUrl,
const response = await this.request<ExecuteTemplateResult>(`/templates/execute/${params.templateCode}`, 'POST', {
userId: params.userId,
imageUrl: params.imageUrl
});
const data = response.data;
if (typeof data === 'string') {
return data;
}
return data.executionId
return response.data;
} catch (error) {
throw error;
}
}
/**
* 创建新模板
* POST /templates
*/
async createTemplate(template: Partial<Template>): Promise<{ code: string; stripeProductId: string; stripePriceId: string }> {
try {
const response = await this.request<{ code: string; stripeProductId: string; stripePriceId: string }>('/templates', 'POST', template);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 更新模板信息
* PUT /templates/update/:code
*/
async updateTemplate(templateCode: string, updates: Partial<Template>): Promise<{ updated: boolean; stripeSynced: boolean }> {
try {
const response = await this.request<{ updated: boolean; stripeSynced: boolean }>(`/templates/update/${templateCode}`, 'POST', updates);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 删除模板
* DELETE /templates/delete/:code
*/
async deleteTemplate(templateCode: string): Promise<{ deleted: boolean }> {
try {
const response = await this.request<{ deleted: boolean }>(`/templates/delete/${templateCode}`, 'POST');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 激活模板并同步到Stripe
* POST /templates/activate/:code
*/
async activateTemplate(templateCode: string): Promise<{ isActive: boolean; stripeSynced: boolean }> {
try {
const response = await this.request<{ isActive: boolean; stripeSynced: boolean }>(`/templates/activate/${templateCode}`, 'POST');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 禁用模板
* POST /templates/deactivate/:code
*/
async deactivateTemplate(templateCode: string): Promise<{ isActive: boolean; stripeSynced: boolean }> {
try {
const response = await this.request<{ isActive: boolean; stripeSynced: boolean }>(`/templates/deactivate/${templateCode}`, 'POST');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 同步模板到Stripe
* POST /templates/sync/:code
*/
async syncTemplateToStripe(templateCode: string, forceUpdate = false): Promise<{ synced: boolean; stripeProductId: string; stripePriceId: string }> {
try {
const response = await this.request<{ synced: boolean; stripeProductId: string; stripePriceId: string }>(`/templates/sync/${templateCode}`, 'POST', {
forceUpdate
});
return response.data;
} catch (error) {
throw error;
}
}
/**
* 批量操作模板
* POST /templates/bulk
*/
async bulkOperationTemplates(params: BulkOperationParams): Promise<{ successful: string[]; failed: string[]; total: number }> {
try {
const response = await this.request<{ successful: string[]; failed: string[]; total: number }>('/templates/bulk', 'POST', params);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 同步所有模板到Stripe
* GET /templates/sync-all-stripe
*/
async syncAllTemplatesToStripe(): Promise<{ successful: number; failed: number; total: number }> {
try {
const response = await this.request<{ successful: number; failed: number; total: number }>('/templates/sync-all-stripe');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 检查模板-Stripe同步状态
* GET /templates/sync-status
*/
async getTemplateSyncStatus(): Promise<{ totalTemplates: number; withStripeProduct: number; activeTemplates: number; needsSync: number; templates: TemplateSyncStatus[] }> {
try {
const response = await this.request<{ totalTemplates: number; withStripeProduct: number; activeTemplates: number; needsSync: number; templates: TemplateSyncStatus[] }>('/templates/sync-status');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 验证模板Stripe同步状态
* GET /templates/verify-sync/:code
*/
async verifyTemplateSync(templateCode: string): Promise<{ templateCode: string; synced: boolean; issues: string[]; stripeProductId?: string; stripePriceId?: string; recommendations: string[] }> {
try {
const response = await this.request<{ templateCode: string; synced: boolean; issues: string[]; stripeProductId?: string; stripePriceId?: string; recommendations: string[] }>(`/templates/verify-sync/${templateCode}`);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 诊断Stripe环境和配置
* GET /templates/diagnose-stripe
*/
async diagnoseStripe(): Promise<{ environment: string; apiKeyValid: boolean; issues: string[]; accountInfo: any; recommendations: string[] }> {
try {
const response = await this.request<{ environment: string; apiKeyValid: boolean; issues: string[]; accountInfo: any; recommendations: string[] }>('/templates/diagnose-stripe');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 模板服务健康检查
* GET /templates/health
*/
async getTemplateHealth(): Promise<{ totalTemplates: number; timestamp: string; service: string }> {
try {
const response = await this.request<{ totalTemplates: number; timestamp: string; service: string }>('/templates/health');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 初始化模板数据
* GET /templates/init
*/
async initTemplates(): Promise<{ total: number; imported: number; failed: number; details: Array<{ code: string; status: string; error?: string }> }> {
try {
const response = await this.request<{ total: number; imported: number; failed: number; details: Array<{ code: string; status: string; error?: string }> }>('/templates/init');
return response.data;
} catch (error) {
throw error;
}
}
/**
* 创建测试模板
* POST /templates/test/create
*/
async createTestTemplate(): Promise<{ code: string; stripeProductId: string; stripePriceId: string }> {
try {
const response = await this.request<{ code: string; stripeProductId: string; stripePriceId: string }>('/templates/test/create', 'POST');
return response.data;
} catch (error) {
throw error;
}
@@ -226,13 +573,13 @@ export class SdkServer {
}
/**
* 获取用户信息 可检测token是否过期
* 获取用户信息 可检测token是否过期(兼容方法)
* @returns
*/
async profile() {
async profile(): Promise<GoogleUserInfo> {
try {
const response = await this.request<{ tokens: IToken }>(`/auth/google/userinfo`, 'GET', {});
return response.data
const response = await this.request<GoogleUserInfo>('/auth/google/userinfo');
return response.data;
} catch (error) {
throw error;
}
@@ -257,39 +604,253 @@ export class SdkServer {
}
/**
* 获取任务执行详情
* @param taskId
* @returns
* 获取执行进度
* GET /templates/execution/:taskId/progress
*/
async getTaskProgress(taskId: string) {
async getTaskProgress(taskId: string): Promise<TaskProgress> {
try {
console.log(`task id is : ${taskId}`)
const response = await this.request<any>(`/templates/execution/${taskId}/progress`, 'GET', {});
console.log(`getTaskProgress response:`, response.data)
return response.data
console.log(`🎨 Getting task progress for: ${taskId}`);
const response = await this.request<TaskProgress>(`/templates/execution/${taskId}/progress`);
console.log(`📊 Task progress response:`, response.data);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 获取我的执行日志
* 获取用户执行历史
* GET /templates/executions/user/:userId
*/
async getMineLogs() {
async getUserExecutions(userId?: string): Promise<UserExecution[]> {
try {
const userId = Taro.getStorageSync(TOKEN_UID_KEY);
const response = await this.request<{ executions: any[] }>(`/templates/executions/user/${userId}`, 'GET', {});
return response.data.executions
const uid = userId || Taro.getStorageSync(TOKEN_UID_KEY);
if (!uid) {
throw new Error('用户ID不存在');
}
const response = await this.request<{ executions: UserExecution[]; total: number }>(`/templates/executions/user/${uid}`);
return response.data.executions || [];
} catch (error) {
throw error;
}
}
/**
* 获取我的执行日志(兼容方法)
*/
async getMineLogs(): Promise<UserExecution[]> {
return this.getUserExecutions();
}
// ==================== 支付相关接口 ====================
/**
* 创建Stripe结账会话
* POST /payment/checkout/:templateCode
*/
async createCheckoutSession(params: CreateCheckoutParams): Promise<CheckoutSessionResult> {
try {
const response = await this.request<CheckoutSessionResult>(`/payment/checkout/${params.templateCode}`, 'POST', {
userId: params.userId,
metadata: params.metadata
});
return response.data;
} catch (error) {
throw error;
}
}
/**
* 处理支付成功回调
* GET /payment/success
*/
async handlePaymentSuccess(sessionId: string, paymentId: string): Promise<{ payment: any; execution: ExecuteTemplateResult }> {
try {
const response = await this.request<{ payment: any; execution: ExecuteTemplateResult }>('/payment/success', 'GET', {
session_id: sessionId,
payment_id: paymentId
});
return response.data;
} catch (error) {
throw error;
}
}
/**
* 处理支付取消
* GET /payment/cancel
*/
async handlePaymentCancel(sessionId: string, paymentId: string): Promise<{ payment: any }> {
try {
const response = await this.request<{ payment: any }>('/payment/cancel', 'GET', {
session_id: sessionId,
payment_id: paymentId
});
return response.data;
} catch (error) {
throw error;
}
}
/**
* 获取用户支付历史
* GET /payment/history
*/
async getPaymentHistory(userId: string): Promise<{ payments: PaymentHistory[]; total: number }> {
try {
const response = await this.request<{ payments: PaymentHistory[]; total: number }>('/payment/history', 'GET', {
userId
});
return response.data;
} catch (error) {
throw error;
}
}
/**
* 处理退款
* POST /payment/refund/:paymentId
*/
async processRefund(paymentId: string, params: RefundParams): Promise<{ refundId: string; amount: number; status: string }> {
try {
const response = await this.request<{ refundId: string; amount: number; status: string }>(`/payment/refund/${paymentId}`, 'POST', params);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 获取支付详情
* GET /payment/:paymentId
*/
async getPaymentDetails(paymentId: string): Promise<any> {
try {
const response = await this.request<any>(`/payment/${paymentId}`);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 支付服务健康检查
* GET /payment/health
*/
async getPaymentHealth(): Promise<{ timestamp: string; service: string }> {
try {
const response = await this.request<{ timestamp: string; service: string }>('/payment/health');
return response.data;
} catch (error) {
throw error;
}
}
// ==================== 任务管理相关接口 ====================
/**
* 获取任务状态和详情
* GET /task/:taskId
*/
async getTaskDetails(taskId: string): Promise<TaskProgress> {
try {
const response = await this.request<TaskProgress>(`/task/${taskId}`);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 创建新任务
* POST /task
*/
async createTask(params: CreateTaskParams): Promise<string> {
try {
const response = await this.request<string>('/task', 'POST', params);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 使用指定ID创建任务
* POST /task/:taskId
*/
async createTaskWithId(taskId: string, params: Omit<CreateTaskParams, 'userId'>): Promise<string> {
try {
const response = await this.request<string>(`/task/${taskId}`, 'POST', params);
return response.data;
} catch (error) {
throw error;
}
}
// ==================== Google OAuth认证相关接口 ====================
/**
* 启动Google OAuth授权流程
* GET /auth/google/authorize
*/
generateGoogleAuthUrl(redirectUrl?: string, scopes?: string): string {
const params = new URLSearchParams();
if (redirectUrl) params.set('redirect_url', redirectUrl);
if (scopes) params.set('scopes', scopes);
const queryString = params.toString();
return `${this.baseUrl}/auth/google/authorize${queryString ? '?' + queryString : ''}`;
}
/**
* 刷新OAuth访问令牌
* POST /auth/google/refresh
*/
async refreshGoogleToken(params: RefreshTokenParams): Promise<TokenResponse> {
try {
const response = await this.request<TokenResponse>('/auth/google/refresh', 'POST', params);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 从google获取用户信息
* GET /auth/google/userinfo
*/
async getGoogleUserInfo(accessToken?: string): Promise<GoogleUserInfo> {
try {
const url = accessToken ? `/auth/google/userinfo?access_token=${accessToken}` : '/auth/google/userinfo';
const response = await this.request<GoogleUserInfo>(url);
return response.data;
} catch (error) {
throw error;
}
}
/**
* 撤销OAuth令牌
* POST /auth/google/revoke
*/
async revokeGoogleToken(token: string, userId?: string): Promise<void> {
try {
await this.request('/auth/google/revoke', 'POST', {
token,
user_id: userId
});
} catch (error) {
throw error;
}
}
// ==================== 其他工具方法 ====================
/**
* 检查服务器连接状态
*/
async checkConnection(): Promise<boolean> {
try {
await this.getAllTemplates();
await this.getTemplateHealth();
return true;
} catch (error) {
console.error('Server connection check failed:', error);
@@ -299,6 +860,8 @@ export class SdkServer {
/**
* 获取认证头部
* 自动从Taro存储中读取访问令牌并添加到Authorization头部
* @returns 认证头部对象
*/
private getAuthHeaders(): Record<string, string> {
try {
@@ -309,37 +872,45 @@ export class SdkServer {
};
}
} catch (error) {
console.warn('Failed to get access token from storage:', error);
console.warn('⚠️ Failed to get access token from storage:', error);
}
return {};
}
/**
* 存储访问令牌
* 存储访问令牌和用户ID
* 将OAuth访问令牌和用户ID保存到本地存储中
* @param token OAuth访问令牌
* @param uid 用户唯一标识
*/
setAccessToken(token: string, uid: string): void {
try {
Taro.setStorageSync(TOKEN_STORAGE_KEY, token);
Taro.setStorageSync(TOKEN_UID_KEY, uid)
Taro.setStorageSync(TOKEN_UID_KEY, uid);
console.log('🔑 Access token and user ID stored successfully');
} catch (error) {
console.error('Failed to store access token:', error);
console.error('Failed to store access token:', error);
}
}
/**
* 清除访问令牌
* 清除访问令牌和用户ID
* 从本地存储中移除访问令牌和用户ID通常在登出时调用
*/
clearAccessToken(): void {
try {
Taro.removeStorageSync(TOKEN_STORAGE_KEY);
Taro.removeStorageSync(TOKEN_UID_KEY);
console.log('🗑️ Access token and user ID cleared successfully');
} catch (error) {
console.error('Failed to clear access token:', error);
console.error('Failed to clear access token:', error);
}
}
/**
* 获取基础URL
* 获取API基础URL
* @returns 当前配置的API基础URL
*/
getBaseUrl(): string {
return this.baseUrl;
@@ -347,8 +918,10 @@ export class SdkServer {
/**
* 设置请求超时时间
* @param timeout 超时时间(毫秒)
*/
setTimeout(timeout: number): void {
(this as any).timeout = timeout;
console.log(`⏱️ Request timeout set to ${timeout}ms`);
}
}