Files
expo-popcore-app/lib/auth.ts
imeepos e1340fa101 feat: 实现 API 接口对接功能 (删除作品、作品搜索、修改密码)
按照 TDD 规范完成三个核心功能的接口对接:

## 新增功能

### 1. 删除作品功能 (app/generationRecord.tsx)
- 新增 use-template-generation-actions.ts hook
- 支持单个删除和批量删除作品
- 删除确认对话框
- 删除成功后自动刷新列表
- 完整的错误处理和加载状态

### 2. 作品搜索功能 (app/searchWorksResults.tsx)
- 新增 use-works-search.ts hook
- 替换模拟数据为真实 SDK 接口
- 支持关键词搜索和分类筛选
- 支持分页加载
- 完整的加载、错误、空结果状态处理

### 3. 修改密码功能 (app/changePassword.tsx)
- 新增 use-change-password.ts hook
- 使用 Better Auth 的 changePassword API
- 客户端表单验证(密码长度、确认密码匹配等)
- 成功后自动返回并提示

## 技术实现
- 严格遵循 TDD 规范(先写测试,后写实现)
- 新增 3 个 hooks 和对应的单元测试
- 更新中英文翻译文件
- 更新 jest.setup.js 添加必要的 mock

## 文档
- 新增 api_integration_report.md - API 对接分析报告
- 新增 api_integration_development_plan.md - 开发计划和完成汇总

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 19:15:24 +08:00

129 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'reflect-metadata'
import { expoClient } from '@better-auth/expo/client'
import { createSkerClientPlugin } from '@repo/sdk'
import {
adminClient,
emailOTPClient,
genericOAuthClient,
jwtClient,
organizationClient,
phoneNumberClient,
usernameClient,
} from 'better-auth/client/plugins'
import { createAuthClient } from 'better-auth/react'
import { fetchWithLogger, TOKEN_KEY } from './fetch-logger'
import type { Subscription } from './plugins/stripe'
import { stripeClient } from './plugins/stripe-plugin'
import { storage } from './storage'
import type { ApiError } from './types'
// 商户ID配置 - 从环境变量或应用配置中读取
export const OWNER_ID = 't0m9cketSQdCA6cHXI9mXQLJPM9LDIw5'
export interface CreditBalance {
tokenUsage: number
remainingTokenBalance: number
currentCreditBalance: number
unitPrice: number
}
export interface SubscriptionListItem extends Subscription {
type?: 'metered' | 'licenced'
limits?: Record<string, number>
creditBalance?: CreditBalance
highestTierPlan?: string
highestTierCredits?: number
}
export interface SubscriptionListParams {
query?: {
referenceId?: string
}
}
export interface SubscriptionRestoreParams {
referenceId?: string
subscriptionId?: string
}
export interface SubscriptionRestoreResponse {
success: boolean
subscription: {
id: string
stripeSubscriptionId: string
cancelAtPeriodEnd: boolean
periodEnd?: Date
status: string
}
}
export interface BillingPortalParams {
locale?: string
referenceId?: string
returnUrl?: string
}
export interface BillingPortalResponse {
url: string
redirect: boolean
}
export interface ISubscription {
list: (params?: SubscriptionListParams) => Promise<{ data?: SubscriptionListItem[]; error?: ApiError }>
restore: (params?: SubscriptionRestoreParams) => Promise<{ data?: SubscriptionRestoreResponse; error?: ApiError }>
billingPortal: (params?: BillingPortalParams) => Promise<{ data?: BillingPortalResponse; error?: ApiError }>
}
// 统一的 Token 存储键名(与 fetch-logger.ts 保持一致)
export const getAuthToken = async () => (await storage.getItem(TOKEN_KEY)) || ''
export const setAuthToken = async (token: string) => {
await storage.setItem(TOKEN_KEY, token)
}
export const authClient = createAuthClient({
baseURL: 'https://api.mixvideo.bowong.cc',
trustedOrigins: ['duooomi://', 'https://api.mixvideo.bowong.cc'],
storage,
scheme: 'duooomi',
fetchOptions: {
headers: {
'Content-Type': 'application/json',
// x-ownerid: 商户ID如果后端需要
// 如果 MERCHANT_ID 为空,则不添加此 header
...(OWNER_ID && { 'x-ownerid': OWNER_ID }),
},
auth: {
type: 'Bearer',
token: async () => {
const Authorization = await getAuthToken()
return Authorization
},
},
customFetchImpl: fetchWithLogger as typeof fetch,
},
plugins: [
createSkerClientPlugin(),
stripeClient(),
usernameClient(),
phoneNumberClient(),
emailOTPClient(),
genericOAuthClient(),
jwtClient(),
adminClient(),
organizationClient(),
expoClient({
storage: storage as any,
}),
],
})
export const { signIn, signUp, signOut, useSession, $Infer, admin, forgetPassword, resetPassword, emailOtp, changePassword } =
authClient
// 导出 loomart API来自 createSkerClientPlugin
export const loomart = Reflect.get(authClient, 'loomart')
// 导出 subscription API
export const subscription: ISubscription = Reflect.get(authClient, 'subscription')