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:
956
API.md
Normal file
956
API.md
Normal 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
|
||||
@@ -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`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user