qing-client 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # qing-client
2
2
 
3
- Qing 平台统一 SDK - 插件化架构 (v2)
3
+ Qing 平台统一 SDK - 插件化架构
4
4
 
5
5
  ---
6
6
 
@@ -11,6 +11,7 @@ Qing 平台统一 SDK - 插件化架构 (v2)
11
11
  - **前后端统一**:一套 SDK 支持前端(网关)和后端(直连)两种模式
12
12
  - **自动 Token 管理**:全局 setToken/clearToken 自动同步到所有服务
13
13
  - **服务隔离**:每个服务独立目录,互不影响
14
+ - **HTTP 错误监控**:支持 `onHttpError` / `onUnauthorized` 回调,便于统一处理
14
15
 
15
16
  ---
16
17
 
@@ -82,37 +83,39 @@ await client.setToken('xxx');
82
83
 
83
84
  ---
84
85
 
85
- ## 可用服务(17 个)
86
+ ## 可用服务(15 个)
86
87
 
87
88
  ### 核心服务
88
89
 
89
- | 服务 | 说明 | 注册名 |
90
- |------|------|--------|
91
- | AuthService | 认证与登录 | `auth` |
92
- | MsgService | 消息中心 | `msg` |
93
- | UserService | 用户管理 | `user` |
94
- | TokenService | Token 管理(微信等) | `token` |
95
- | FileService | 文件服务 | `file` / `files` |
90
+ | 服务 | 说明 | 注册名 | API 文档 |
91
+ |------|------|--------|----------|
92
+ | AuthService | 认证与登录 | `auth` | [auth.md](./docs/api/auth.md) |
93
+ | MsgService | 消息中心 / 邮件 / 飞书 | `msg` | [msg.md](./docs/api/msg.md) |
94
+ | UserService | 用户管理 | `user` | [user.md](./docs/api/user.md) |
95
+ | TokenService | 微信 Token 管理 | `token` | [token.md](./docs/api/token.md) |
96
+ | FileService | 文件与文件夹管理 | `file` | [file.md](./docs/api/file.md) |
96
97
 
97
98
  ### AI 相关
98
99
 
99
- | 服务 | 说明 | 注册名 |
100
- |------|------|--------|
101
- | AiService | AI 对话/会话 | `ai` |
102
- | AigcService | AIGC 能力 | `aigc` |
103
- | ProviderService | 大模型供应商 | `providers` |
104
- | UsageService | 用量统计 | `providers` |
100
+ | 服务 | 说明 | 注册名 | API 文档 |
101
+ |------|------|--------|----------|
102
+ | AiService | AI 对话 / 助手 / 会话 | `ai` | [ai.md](./docs/api/ai.md) |
103
+ | AigcService | AIGC 生成与图像处理 | `aigc` | [aigc.md](./docs/api/aigc.md) |
104
+ | ProviderService | 大模型供应商管理 | `provider` | [provider.md](./docs/api/provider.md) |
105
+ | UsageService | Token 用量统计 | `usage` | [usage.md](./docs/api/usage.md) |
105
106
 
106
107
  ### 业务服务
107
108
 
108
- | 服务 | 说明 | 注册名 |
109
- |------|------|--------|
110
- | AuditLogService | 审计日志 | `logs` |
111
- | FrontHostService | 静态 HTML 托管 | `gateway-h5` |
112
- | OrgService | 组织与多租户 | `org` |
113
- | DeliveryStreamService | 投递流 | `delivery-stream` |
114
- | EzAbilityService | Ez AI 能力 | `ez-ability` |
115
- | ImService | IM 群组 | `im` |
109
+ | 服务 | 说明 | 注册名 | API 文档 |
110
+ |------|------|--------|----------|
111
+ | AuditLogService | 审计日志 | `audit` | [audit.md](./docs/api/audit.md) |
112
+ | FrontHostService | 前端 HTML 托管 | `fronthost` | [fronthost.md](./docs/api/fronthost.md) |
113
+ | OrgService | 组织 / 项目 / 应用管理 | `org` | [org.md](./docs/api/org.md) |
114
+ | DeliveryStreamService | 投递流 / 版本 / 需求 | `deliveryStream` | [delivery-stream.md](./docs/api/delivery-stream.md) |
115
+ | EzAbilityService | AI 需求枚举与 PRD 生成 | `ezAbility` | [ez-ability.md](./docs/api/ez-ability.md) |
116
+ | ImService | IM 群组与消息 | `im` | [im.md](./docs/api/im.md) |
117
+
118
+ > **注册名** 即 `client.services.<注册名>` 中的 key。完整 API 参考见 [docs/api/](./docs/api/README.md)。
116
119
 
117
120
  ---
118
121
 
@@ -213,13 +216,30 @@ client.setUserContext({
213
216
 
214
217
  ---
215
218
 
219
+ ## HTTP 错误监控
220
+
221
+ ```typescript
222
+ const client = new Client({
223
+ gatewayUrl: '...',
224
+ onHttpError(statusCode, error, ctx) {
225
+ console.error(`[${ctx.serviceName}] ${ctx.path} → ${statusCode}`);
226
+ if (statusCode >= 500) reportToSentry(error);
227
+ },
228
+ onUnauthorized() {
229
+ router.push('/login');
230
+ },
231
+ });
232
+ ```
233
+
234
+ ---
235
+
216
236
  ## 新增服务
217
237
 
218
238
  参见 [SDK-GENERATION.md](./docs/SDK-GENERATION.md)
219
239
 
220
240
  1. 在 `src/services/{name}/` 创建服务目录
221
241
  2. 生成 `types.ts` 和 `{Name}Service.ts`
222
- 3. 在 `src/services/index.ts` 和 `src/index.ts` 添加导出
242
+ 3. 在 `src/index.ts` 添加导出
223
243
  4. 使用方通过 `.use(YourService)` 注册
224
244
 
225
245
  ---
@@ -233,11 +253,11 @@ src/
233
253
  │ ├── BaseClient.ts # 服务基类
234
254
  │ └── index.ts
235
255
  ├── types/ # 公共类型和契约
236
- │ ├── common.ts # 通用类型
237
- │ ├── config.ts # 配置类型
238
- │ ├── service-contract.ts # 服务契约
256
+ │ ├── common.ts # 通用类型(ApiResponse / TokenStorage 等)
257
+ │ ├── config.ts # 配置类型(ClientConfig)
258
+ │ ├── service-contract.ts # 服务契约(ServicePlugin / TokenAware 等)
239
259
  │ └── index.ts
240
- ├── services/ # 服务目录(17 个服务)
260
+ ├── services/ # 服务目录(15 个服务)
241
261
  │ ├── auth/ # 认证服务
242
262
  │ ├── msg/ # 消息服务
243
263
  │ ├── user/ # 用户服务
@@ -255,7 +275,7 @@ src/
255
275
  │ ├── im/ # IM 服务
256
276
  │ └── index.ts
257
277
  ├── docs/
258
- │ └── SDK-GENERATION.md # 生成指南
278
+ │ └── SDK-GENERATION.md # 服务生成指南
259
279
  └── index.ts # 包入口
260
280
  ```
261
281
 
@@ -270,24 +290,12 @@ npm install
270
290
  # 构建
271
291
  npm run build
272
292
 
273
- # 开发模式
274
- npm run dev
293
+ # 发布
294
+ npm run rele
275
295
  ```
276
296
 
277
297
  ---
278
298
 
279
- ## 与旧版对比
280
-
281
- | 方面 | 旧版 (v0.x) | 新版 (v2.0) |
282
- |------|------------|-------------|
283
- | 新增服务 | 改 6+ 文件 | 改 2 文件 + 注册 |
284
- | 类型推导 | 手动维护 | Module Augmentation 自动 |
285
- | Token 管理 | 遍历硬编码 | 自动收集 TokenAware |
286
- | 服务隔离 | 耦合在一起 | 完全独立目录 |
287
- | 代码重复 | setToken 遍历 16 次 | 自动收集处理 |
288
-
289
- ---
290
-
291
299
  ## License
292
300
 
293
301
  MIT
@@ -0,0 +1,327 @@
1
+ # SDK 服务生成指南
2
+
3
+ 本文档描述如何为新的后端服务生成对应的 SDK 代码。
4
+
5
+ ---
6
+
7
+ ## 目录结构约定
8
+
9
+ ```
10
+ src/
11
+ ├── core/ # 核心框架(不要修改)
12
+ │ ├── Client.ts # 主客户端
13
+ │ ├── BaseClient.ts # 服务基类
14
+ │ └── index.ts
15
+ ├── types/ # 公共类型(不要修改)
16
+ │ ├── common.ts
17
+ │ ├── config.ts
18
+ │ ├── service-contract.ts
19
+ │ └── index.ts
20
+ ├── services/ # 服务目录
21
+ │ ├── auth/ # 示例服务
22
+ │ │ ├── AuthService.ts # 服务实现
23
+ │ │ ├── types.ts # 类型定义
24
+ │ │ └── index.ts # 导出
25
+ │ ├── msg/
26
+ │ │ └── ...
27
+ │ └── {新服务名}/ # 新服务放这里
28
+ │ └── ...
29
+ ├── docs/
30
+ │ └── SDK-GENERATION.md # 本文档
31
+ └── index.ts # 包入口
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 生成步骤
37
+
38
+ ### 第一步:创建服务目录
39
+
40
+ 在 `src/services/` 下创建以服务名命名的目录(如 `im/`)。
41
+
42
+ ```
43
+ src/services/im/
44
+ ├── ImService.ts
45
+ ├── types.ts
46
+ └── index.ts
47
+ ```
48
+
49
+ ---
50
+
51
+ ### 第二步:生成类型定义 (`types.ts`)
52
+
53
+ 根据后端 API 接口定义,生成对应的 TypeScript 类型。
54
+
55
+ ```typescript
56
+ // src/services/im/types.ts
57
+
58
+ export interface Group {
59
+ id: string;
60
+ name: string;
61
+ ownerId: string;
62
+ memberCount: number;
63
+ createdAt: string;
64
+ }
65
+
66
+ export interface CreateGroupRequest {
67
+ name: string;
68
+ memberIds: string[];
69
+ requireAdmin?: boolean;
70
+ }
71
+
72
+ export interface GroupQueryParams {
73
+ page?: number;
74
+ limit?: number;
75
+ }
76
+
77
+ // ... 其他类型
78
+ ```
79
+
80
+ ---
81
+
82
+ ### 第三步:生成服务实现 (`ImService.ts`)
83
+
84
+ **必须遵循以下模板**:
85
+
86
+ ```typescript
87
+ // src/services/im/ImService.ts
88
+
89
+ import { BaseClient } from '../../core/BaseClient';
90
+ import { ClientConfig, TokenStorage, RequestOptions } from '../../types';
91
+ import { Group, CreateGroupRequest, GroupQueryParams } from './types';
92
+
93
+ /**
94
+ * IM 群组服务
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const groups = await client.services.im.getGroups();
99
+ * ```
100
+ */
101
+ export class ImService extends BaseClient {
102
+ // ========== 必须的静态属性 ==========
103
+ /** 服务名称(用于注册到 client.services 的 key) */
104
+ static readonly serviceName = 'im';
105
+
106
+ /** API 路径(对应 /api/im) */
107
+ static readonly servicePath = 'im';
108
+
109
+ // ========== 必须的实例属性 ==========
110
+ get serviceName(): string {
111
+ return 'im';
112
+ }
113
+
114
+ // ========== 构造函数 ==========
115
+ constructor(config: ClientConfig, tokenStorage: TokenStorage) {
116
+ super(config, 'im', tokenStorage);
117
+ }
118
+
119
+ // ========== 业务方法 ==========
120
+
121
+ async getGroups(params?: GroupQueryParams, options?: RequestOptions): Promise<Group[]> {
122
+ return this.request<Group[]>('/groups', {
123
+ ...options,
124
+ method: 'GET',
125
+ params,
126
+ });
127
+ }
128
+
129
+ async createGroup(request: CreateGroupRequest, options?: RequestOptions): Promise<Group> {
130
+ return this.request<Group>('/groups', {
131
+ ...options,
132
+ method: 'POST',
133
+ body: request,
134
+ });
135
+ }
136
+
137
+ // ... 其他方法
138
+ }
139
+
140
+ // ========== 必须的类型扩展 ==========
141
+ /**
142
+ * 扩展 Client.Services 接口
143
+ * 使 client.services.im 具有完整类型推导
144
+ */
145
+ declare module '../../core/Client' {
146
+ interface Services {
147
+ im: ImService;
148
+ }
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ### 第四步:创建导出文件 (`index.ts`)
155
+
156
+ ```typescript
157
+ // src/services/im/index.ts
158
+
159
+ export { ImService } from './ImService';
160
+ export * from './types';
161
+ ```
162
+
163
+ ---
164
+
165
+ ### 第五步:在包入口添加导出
166
+
167
+ 在 `src/index.ts` 中添加服务类和类型的导出:
168
+
169
+ ```typescript
170
+ // src/index.ts
171
+
172
+ // ... 已有代码 ...
173
+
174
+ // ========== 服务 ==========
175
+ export { ImService } from './services/im/ImService'; // 新增
176
+
177
+ // ========== 服务类型 ==========
178
+ export type {
179
+ Group,
180
+ CreateGroupRequest,
181
+ GroupQueryParams,
182
+ } from './services/im/types'; // 新增
183
+ ```
184
+
185
+ ---
186
+
187
+ ### 第六步(如需后端直连):在 ClientConfig 中添加服务 URL
188
+
189
+ 如果需要后端模式直连该服务,需在 `src/types/config.ts` 的 `ClientConfig` 接口中添加对应的 URL 字段:
190
+
191
+ ```typescript
192
+ export interface ClientConfig {
193
+ // ...
194
+ /** IM 服务地址 */
195
+ imServiceUrl?: string;
196
+ // ...
197
+ }
198
+ ```
199
+
200
+ ---
201
+
202
+ ## 服务类必须实现的接口
203
+
204
+ ```typescript
205
+ class YourService extends BaseClient {
206
+ static readonly serviceName = 'yourService'; // 必填:注册到 client.services 的 key
207
+ static readonly servicePath = 'your-service'; // 必填:API 路径前缀
208
+
209
+ get serviceName(): string { return 'yourService'; } // 必填:实例属性
210
+
211
+ constructor(config: ClientConfig, tokenStorage: TokenStorage) {
212
+ super(config, 'your-service', tokenStorage); // servicePath 传给 BaseClient
213
+ }
214
+
215
+ // 业务方法...
216
+ }
217
+
218
+ // 类型扩展(必填)
219
+ declare module '../../core/Client' {
220
+ interface Services {
221
+ yourService: YourService;
222
+ }
223
+ }
224
+ ```
225
+
226
+ > **注意**:`serviceName`(camelCase)用于注册和访问 `client.services.xxx`;`servicePath`(kebab-case)用于拼接 API URL `/api/xxx`。两者可能不同。
227
+
228
+ ---
229
+
230
+ ## 请求方法说明
231
+
232
+ BaseClient 提供了两个请求方法:
233
+
234
+ ### `request<T>(path, options)`
235
+
236
+ 用于普通请求。
237
+
238
+ ```typescript
239
+ // GET 请求
240
+ return this.request<User>('/user/123', {
241
+ method: 'GET',
242
+ });
243
+
244
+ // POST 请求
245
+ return this.request<User>('/user', {
246
+ method: 'POST',
247
+ body: userData,
248
+ });
249
+
250
+ // 带查询参数
251
+ return this.request<User[]>('/users', {
252
+ method: 'GET',
253
+ params: { page: 1, limit: 10 },
254
+ });
255
+ ```
256
+
257
+ ### `paginatedRequest<T>(path, options)`
258
+
259
+ 用于分页请求,返回带 pagination 的响应。
260
+
261
+ ```typescript
262
+ return this.paginatedRequest<User>('/users', {
263
+ method: 'GET',
264
+ params: { page: 1, limit: 10 },
265
+ });
266
+ // 返回: { success, data: User[], pagination: { page, perPage, total, totalPages } }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## 使用方注册示例
272
+
273
+ ```typescript
274
+ import { Client, AuthService, MsgService, ImService } from 'qing-client';
275
+
276
+ const client = new Client({
277
+ gatewayUrl: 'https://api.example.com',
278
+ projectId: 'xxx',
279
+ })
280
+ .use(AuthService)
281
+ .use(MsgService)
282
+ .use(ImService);
283
+
284
+ await client.setToken('xxx');
285
+
286
+ // 完整类型推导
287
+ client.services.im.getGroups();
288
+ ```
289
+
290
+ ---
291
+
292
+ ## 检查清单
293
+
294
+ 生成新服务后,请检查:
295
+
296
+ - [ ] 服务目录已创建在 `src/services/{name}/`
297
+ - [ ] `types.ts` 包含所有请求/响应类型
298
+ - [ ] 服务类继承 `BaseClient`
299
+ - [ ] 静态属性 `serviceName` 和 `servicePath` 已定义
300
+ - [ ] 实例属性 `get serviceName()` 已实现(返回值与静态 `serviceName` 一致)
301
+ - [ ] 构造函数签名为 `(config: ClientConfig, tokenStorage: TokenStorage)`
302
+ - [ ] `declare module` 类型扩展已添加(key 与 `serviceName` 一致)
303
+ - [ ] `index.ts` 导出文件已创建
304
+ - [ ] `src/index.ts` 已添加服务类和类型的导出
305
+ - [ ] (可选)`src/types/config.ts` 已添加后端模式服务 URL 字段
306
+
307
+ ---
308
+
309
+ ## AI 提示词模板
310
+
311
+ 如果使用 AI 生成 SDK,可以使用以下提示词:
312
+
313
+ ```
314
+ 请根据以下后端 API 接口定义,生成 qing-client SDK 的服务代码。
315
+
316
+ 接口定义:
317
+ [粘贴 API 文档或接口描述]
318
+
319
+ 要求:
320
+ 1. 遵循 SDK-GENERATION.md 中的目录结构和代码模板
321
+ 2. 服务名为 {service-name}
322
+ 3. 生成 types.ts(类型定义)和 {ServiceName}.ts(服务实现)
323
+ 4. 必须包含静态属性 serviceName 和 servicePath
324
+ 5. 必须在文件末尾添加 declare module 类型扩展
325
+ 6. 所有方法使用 this.request<T>() 进行请求
326
+ 7. 添加完整的 JSDoc 注释
327
+ ```
@@ -0,0 +1,81 @@
1
+ # API 参考文档
2
+
3
+ qing-client SDK 所有服务的 API 文档索引。
4
+
5
+ 每个文档包含:方法列表、参数类型、返回值类型、使用示例。
6
+
7
+ ---
8
+
9
+ ## 核心服务
10
+
11
+ | 服务 | 说明 | 方法数 | 文档 |
12
+ |------|------|--------|------|
13
+ | AuthService | 认证与登录 | 9 | [auth.md](./auth.md) |
14
+ | MsgService | 消息中心 / 邮件 / 飞书 | 12 | [msg.md](./msg.md) |
15
+ | UserService | 用户管理 | 10 | [user.md](./user.md) |
16
+ | TokenService | 微信 Token 管理 | 5 | [token.md](./token.md) |
17
+ | FileService | 文件与文件夹管理 | 22 | [file.md](./file.md) |
18
+
19
+ ## AI 相关
20
+
21
+ | 服务 | 说明 | 方法数 | 文档 |
22
+ |------|------|--------|------|
23
+ | AiService | AI 对话 / 助手 / 会话 | 30 | [ai.md](./ai.md) |
24
+ | AigcService | AIGC 生成与图像处理 | 14 | [aigc.md](./aigc.md) |
25
+ | ProviderService | 大模型供应商管理 | 16 | [provider.md](./provider.md) |
26
+ | UsageService | Token 用量统计 | 6 | [usage.md](./usage.md) |
27
+
28
+ ## 业务服务
29
+
30
+ | 服务 | 说明 | 方法数 | 文档 |
31
+ |------|------|--------|------|
32
+ | AuditLogService | 审计日志 | 2 | [audit.md](./audit.md) |
33
+ | FrontHostService | 前端 HTML 托管 | 9 | [fronthost.md](./fronthost.md) |
34
+ | OrgService | 组织 / 项目 / 应用管理 | 27 | [org.md](./org.md) |
35
+ | DeliveryStreamService | 投递流 / 版本 / 需求 | 17 | [delivery-stream.md](./delivery-stream.md) |
36
+ | EzAbilityService | AI 需求枚举与 PRD 生成 | 14 | [ez-ability.md](./ez-ability.md) |
37
+ | ImService | IM 群组与消息 | 3 | [im.md](./im.md) |
38
+
39
+ ---
40
+
41
+ ## 通用约定
42
+
43
+ ### RequestOptions
44
+
45
+ 所有方法的最后一个参数都支持 `RequestOptions`,用于覆盖本次请求的上下文:
46
+
47
+ ```typescript
48
+ interface RequestOptions {
49
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
50
+ headers?: Record<string, string>;
51
+ params?: Record<string, any>;
52
+ body?: any;
53
+ projectId?: string; // 覆盖本次请求的项目 ID
54
+ orgId?: string; // 覆盖本次请求的组织 ID
55
+ appId?: string; // 覆盖本次请求的应用 ID
56
+ userContext?: UserContext; // 覆盖本次请求的用户上下文(后端模式)
57
+ }
58
+ ```
59
+
60
+ ### 响应格式
61
+
62
+ SDK 会自动解包 `{ success, data, message }` 格式的响应,方法返回值直接是 `data` 部分。
63
+
64
+ 分页请求返回 `PaginatedResponse<T>`:
65
+
66
+ ```typescript
67
+ interface PaginatedResponse<T> {
68
+ success: boolean;
69
+ data: T[];
70
+ pagination: {
71
+ page: number;
72
+ perPage: number;
73
+ total: number;
74
+ totalPages: number;
75
+ };
76
+ }
77
+ ```
78
+
79
+ ### 错误处理
80
+
81
+ 请求失败时抛出 `Error`,错误消息格式为 `[服务名服务] 错误信息 (路径: /xxx)`。可通过 `ClientConfig.onHttpError` 回调统一处理。