zentao-api 0.1.0 → 0.2.0-beta.2
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/LICENSE +2 -2
- package/README.md +221 -131
- package/dist/browser/zentao-api.global.js +2 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/client/index.d.ts +39 -0
- package/dist/client/index.js +172 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +7 -8
- package/dist/misc/browser-global.d.ts +1 -0
- package/dist/misc/browser-global.js +8 -0
- package/dist/misc/environment.d.ts +8 -0
- package/dist/misc/environment.js +124 -0
- package/dist/misc/errors.d.ts +30 -0
- package/dist/misc/errors.js +40 -0
- package/dist/misc/global-options.d.ts +5 -0
- package/dist/misc/global-options.js +9 -0
- package/dist/modules/generated.d.ts +8 -0
- package/dist/modules/generated.js +4226 -0
- package/dist/modules/registry.d.ts +22 -0
- package/dist/modules/registry.js +142 -0
- package/dist/modules/resolve.d.ts +7 -0
- package/dist/modules/resolve.js +206 -0
- package/dist/profiles/index.d.ts +14 -0
- package/dist/profiles/index.js +205 -0
- package/dist/request/index.d.ts +7 -0
- package/dist/request/index.js +65 -0
- package/dist/types/index.d.ts +296 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +26 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +4 -0
- package/package.json +52 -76
- package/dist/types.d.ts +0 -70
- package/dist/utils.d.ts +0 -93
- package/dist/zentao-api.cjs.development.js +0 -3619
- package/dist/zentao-api.cjs.development.js.map +0 -1
- package/dist/zentao-api.cjs.production.min.js +0 -2
- package/dist/zentao-api.cjs.production.min.js.map +0 -1
- package/dist/zentao-api.esm.js +0 -3611
- package/dist/zentao-api.esm.js.map +0 -1
- package/dist/zentao-config.d.ts +0 -93
- package/dist/zentao-request-builder.d.ts +0 -120
- package/dist/zentao.d.ts +0 -175
- package/dist/zentao12.d.ts +0 -676
- package/src/index.ts +0 -5
- package/src/types.ts +0 -88
- package/src/utils.ts +0 -216
- package/src/zentao-config.ts +0 -150
- package/src/zentao-request-builder.ts +0 -227
- package/src/zentao.ts +0 -596
- package/src/zentao12.ts +0 -1272
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Sun Hao
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,190 +1,280 @@
|
|
|
1
|
-
#
|
|
1
|
+
# zentao-api
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/zentao-api)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
4
6
|
|
|
5
|
-
禅道 API
|
|
7
|
+
Browser & Node.js SDK for [ZenTao](https://www.zentao.net) (禅道) API v2.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
`zentao-api` 是一个面向禅道 API v2 的轻量 JavaScript/TypeScript SDK,可用于 Node.js 18+、浏览器打包工具以及 CDN/script 标签场景。
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
---
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
## 安装 / Install
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install zentao-api
|
|
13
17
|
```
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## 快速开始 / Quick Start
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
### 创建客户端
|
|
18
22
|
|
|
19
|
-
```
|
|
20
|
-
import {
|
|
23
|
+
```ts
|
|
24
|
+
import { ZentaoClient } from 'zentao-api';
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
account: 'demo',
|
|
26
|
-
password: '123456'
|
|
26
|
+
const client = new ZentaoClient({
|
|
27
|
+
baseUrl: 'https://zentao.example.com',
|
|
28
|
+
token: 'your-token',
|
|
27
29
|
});
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
const productAllResult = await zentao
|
|
31
|
-
.m('product')
|
|
32
|
-
.f('all')
|
|
33
|
-
.get();
|
|
34
|
-
|
|
35
|
-
// 输出产品列表
|
|
36
|
-
console.log('All products', productAllResult.data.products);
|
|
37
|
-
|
|
38
|
-
// 调用 product-view 获取产品详细信息
|
|
39
|
-
const productViewResult = await zentao
|
|
40
|
-
.m('product')
|
|
41
|
-
.f('view')
|
|
42
|
-
.withParams({productID: 1})
|
|
43
|
-
.get();
|
|
44
|
-
|
|
45
|
-
// 输出产品信息
|
|
46
|
-
console.log('All products', productViewResult.data.prodcut);
|
|
47
|
-
|
|
48
|
-
// 调用 prodcut-add 添加新的产品到禅道
|
|
49
|
-
const productCreateResult = await zentao
|
|
50
|
-
.m('product')
|
|
51
|
-
.f('create')
|
|
52
|
-
.post({
|
|
53
|
-
name: 'New product',
|
|
54
|
-
code: 'new_product_code'
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (productCreateResult.status) {
|
|
58
|
-
console.log('"New product" added.');
|
|
59
|
-
}
|
|
31
|
+
const products = await client.get('/products');
|
|
60
32
|
```
|
|
61
33
|
|
|
62
|
-
|
|
34
|
+
`baseUrl` 是禅道站点根地址。SDK 会在内部追加 `/api.php/v2`。
|
|
35
|
+
|
|
36
|
+
### 账号密码登录
|
|
37
|
+
|
|
38
|
+
如果还没有 token,可以使用账号密码登录:
|
|
63
39
|
|
|
64
|
-
|
|
40
|
+
```ts
|
|
41
|
+
const client = new ZentaoClient('https://zentao.example.com');
|
|
42
|
+
const token = await client.login('admin', 'password');
|
|
43
|
+
```
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
### 全局客户端与模块请求
|
|
67
46
|
|
|
68
|
-
```
|
|
69
|
-
import {
|
|
47
|
+
```ts
|
|
48
|
+
import { ZentaoClient, request, setGlobalOptions } from 'zentao-api';
|
|
70
49
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
account: 'demo',
|
|
75
|
-
password: '123456'
|
|
50
|
+
ZentaoClient.init({
|
|
51
|
+
baseUrl: 'https://zentao.example.com',
|
|
52
|
+
token: 'your-token',
|
|
76
53
|
});
|
|
77
54
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
setGlobalOptions({ recPerPage: '50' });
|
|
56
|
+
|
|
57
|
+
const result = await request('product/list', {});
|
|
58
|
+
```
|
|
82
59
|
|
|
83
|
-
|
|
84
|
-
const productViewResult = await zentao.getProduct({productID: 1})
|
|
85
|
-
// 输出产品信息
|
|
86
|
-
console.log('All products', productViewResult.data.prodcut);
|
|
60
|
+
单次调用的选项会覆盖全局选项:
|
|
87
61
|
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
62
|
+
```ts
|
|
63
|
+
const result = await request('bug/list', { product: 1 }, { limit: '10' });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 从本地 Profile 恢复
|
|
67
|
+
|
|
68
|
+
SDK 支持将登录信息持久化到本地(Node.js: `~/.config/zentao/zentao.json`,浏览器: `localStorage`),后续可直接恢复客户端:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const client = await ZentaoClient.fromProfile();
|
|
72
|
+
// 或指定 profile key
|
|
73
|
+
const client = await ZentaoClient.fromProfile('admin@https://zentao.example.com');
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API 概览
|
|
77
|
+
|
|
78
|
+
### ZentaoClient
|
|
79
|
+
|
|
80
|
+
| 方法 | 说明 |
|
|
81
|
+
|------|------|
|
|
82
|
+
| `client.get<T>(path)` | GET 请求 |
|
|
83
|
+
| `client.post<T>(path, body)` | POST 请求 |
|
|
84
|
+
| `client.put<T>(path, body)` | PUT 请求 |
|
|
85
|
+
| `client.delete<T>(path)` | DELETE 请求 |
|
|
86
|
+
| `client.login(account, password)` | 账号密码登录,返回 token |
|
|
87
|
+
| `client.request(path, options?)` | 通用请求(底层方法) |
|
|
88
|
+
| `ZentaoClient.init(options)` | 创建全局单例客户端 |
|
|
89
|
+
| `ZentaoClient.create(options)` | 工厂方法创建客户端 |
|
|
90
|
+
| `ZentaoClient.fromProfile(key?)` | 从持久化 profile 恢复客户端 |
|
|
91
|
+
|
|
92
|
+
### 模块请求
|
|
93
|
+
|
|
94
|
+
| 函数 | 说明 |
|
|
95
|
+
|------|------|
|
|
96
|
+
| `request(name, params?, options?)` | 按 `"module/action"` 格式调用已注册模块 |
|
|
97
|
+
| `defineModules(modules, options?)` | 注册或扩展模块定义 |
|
|
98
|
+
| `defineModuleActions(module, actions)` | 为已有模块追加或替换动作 |
|
|
99
|
+
| `getModule(name)` | 获取模块定义 |
|
|
100
|
+
| `getModuleAction(module, action)` | 获取指定动作定义 |
|
|
101
|
+
| `setGlobalOptions(options)` | 设置全局默认选项 |
|
|
102
|
+
| `getGlobalOptions()` | 获取当前全局选项 |
|
|
103
|
+
|
|
104
|
+
## 错误处理
|
|
105
|
+
|
|
106
|
+
SDK 所有传输层错误均通过 `ZentaoError` 抛出,包含稳定的错误码:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { ZentaoError } from 'zentao-api';
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await client.get('/products');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error instanceof ZentaoError) {
|
|
115
|
+
console.error(error.code); // e.g. 'E_HTTP_ERROR', 'E_TIMEOUT', 'E_NETWORK_ERROR'
|
|
116
|
+
console.error(error.message);
|
|
117
|
+
}
|
|
95
118
|
}
|
|
96
119
|
```
|
|
97
120
|
|
|
98
|
-
`
|
|
121
|
+
> **注意**:服务端返回 `{ status: "fail" }` 时 SDK 不会抛出异常,按原始响应内容返回。仅 HTTP/网络/超时等传输层错误会抛出 `ZentaoError`。
|
|
122
|
+
|
|
123
|
+
## 扩展模块
|
|
124
|
+
|
|
125
|
+
生成的模块定义来自 `scripts/update-registry.ts`。你可以在调用 `request()` 前扩展模块,或新增、替换动作。
|
|
99
126
|
|
|
100
|
-
|
|
101
|
-
* addDept
|
|
102
|
-
* addProduct
|
|
103
|
-
* addProject
|
|
104
|
-
* addTask
|
|
105
|
-
* addUser
|
|
106
|
-
* finishTask
|
|
107
|
-
* getBug
|
|
108
|
-
* getBugCreateParams
|
|
109
|
-
* getBugList
|
|
110
|
-
* getBugResolveParams
|
|
111
|
-
* getDeptList
|
|
112
|
-
* getProduct
|
|
113
|
-
* getProductCreateParams
|
|
114
|
-
* getProductList
|
|
115
|
-
* getProject
|
|
116
|
-
* getProjectCreateParams
|
|
117
|
-
* getProjectList
|
|
118
|
-
* getTask
|
|
119
|
-
* getTaskCreateParams
|
|
120
|
-
* getTaskFinishParams
|
|
121
|
-
* getTaskList
|
|
122
|
-
* getUserCreateParams
|
|
123
|
-
* getUserList
|
|
124
|
-
* resolveBug
|
|
127
|
+
### 新增模块
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
```ts
|
|
130
|
+
import { defineModules } from 'zentao-api';
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
defineModules({
|
|
133
|
+
name: 'custom',
|
|
134
|
+
actions: [
|
|
135
|
+
{
|
|
136
|
+
name: 'list',
|
|
137
|
+
type: 'list',
|
|
138
|
+
method: 'GET',
|
|
139
|
+
path: '/custom',
|
|
140
|
+
resultType: 'list',
|
|
141
|
+
resultGetter: 'items',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
});
|
|
145
|
+
```
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
### 为已有模块追加动作
|
|
131
148
|
|
|
132
|
-
|
|
149
|
+
```ts
|
|
150
|
+
import { defineModuleActions } from 'zentao-api';
|
|
133
151
|
|
|
134
|
-
|
|
152
|
+
defineModuleActions('bug', {
|
|
153
|
+
name: 'archive',
|
|
154
|
+
type: 'action',
|
|
155
|
+
method: 'PUT',
|
|
156
|
+
path: '/bugs/{bugID}/archive',
|
|
157
|
+
pathParams: { bugID: 1 },
|
|
158
|
+
resultType: 'text',
|
|
159
|
+
});
|
|
160
|
+
```
|
|
135
161
|
|
|
136
|
-
###
|
|
162
|
+
### 合并与替换
|
|
137
163
|
|
|
138
|
-
|
|
164
|
+
同名模块默认**合并**定义:同名动作会替换,未知动作会追加。如需**整体替换**模块,传入 `{ replace: true }`:
|
|
139
165
|
|
|
140
|
-
```
|
|
141
|
-
|
|
166
|
+
```ts
|
|
167
|
+
defineModules(myModule, { replace: true });
|
|
142
168
|
```
|
|
143
169
|
|
|
144
|
-
|
|
170
|
+
如果扩展定义拆分在多个文件中,请在应用启动入口中显式导入这些文件,确保它们在调用 `request()` 前完成注册。
|
|
145
171
|
|
|
146
|
-
|
|
172
|
+
## TypeScript 支持
|
|
147
173
|
|
|
148
|
-
|
|
174
|
+
SDK 提供完整的 TypeScript 类型定义,所有公共类型均可直接导入:
|
|
149
175
|
|
|
150
|
-
```
|
|
151
|
-
|
|
176
|
+
```ts
|
|
177
|
+
import type {
|
|
178
|
+
ZentaoClientOptions,
|
|
179
|
+
ModuleDefinition,
|
|
180
|
+
ModuleAction,
|
|
181
|
+
ResponseData,
|
|
182
|
+
RequestOptions,
|
|
183
|
+
} from 'zentao-api';
|
|
152
184
|
```
|
|
153
185
|
|
|
154
|
-
|
|
186
|
+
## 浏览器
|
|
155
187
|
|
|
156
|
-
|
|
188
|
+
浏览器打包工具可以正常导入这个包:
|
|
157
189
|
|
|
158
|
-
```
|
|
159
|
-
|
|
190
|
+
```ts
|
|
191
|
+
import { ZentaoClient } from 'zentao-api';
|
|
160
192
|
```
|
|
161
193
|
|
|
162
|
-
|
|
194
|
+
如果使用 script 标签,请使用浏览器构建包,并从 `window.ZentaoAPI` 读取 API:
|
|
163
195
|
|
|
164
|
-
|
|
196
|
+
```html
|
|
197
|
+
<script src="https://cdn.jsdelivr.net/npm/zentao-api@latest/dist/browser/zentao-api.global.js"></script>
|
|
198
|
+
<script>
|
|
199
|
+
console.log(window.ZentaoAPI.VERSION, window.ZentaoAPI.BUILD);
|
|
200
|
+
const client = new window.ZentaoAPI.ZentaoClient('https://zentao.example.com');
|
|
201
|
+
</script>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> **CORS**:浏览器直接请求要求禅道服务器允许 CORS。浏览器代码也会把 token 暴露给前端;如果这不可接受,请使用后端代理。
|
|
205
|
+
>
|
|
206
|
+
> **TLS**:`insecure` TLS 选项仅适用于 Node.js,在浏览器运行时会抛出错误。
|
|
165
207
|
|
|
166
|
-
|
|
167
|
-
|
|
208
|
+
## 测试
|
|
209
|
+
|
|
210
|
+
```sh
|
|
211
|
+
bun test # 单元测试
|
|
212
|
+
bun run test:coverage # 含覆盖率的单元测试
|
|
213
|
+
bun run check # 完整 CI 流程:测试 + 类型检查 + 注册表 + 构建 + 冒烟测试
|
|
168
214
|
```
|
|
169
215
|
|
|
170
|
-
###
|
|
216
|
+
### 真实环境测试
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
真实环境测试需要连接到运行中的禅道实例,不包含在默认 `bun test` 中:
|
|
173
219
|
|
|
174
|
-
```
|
|
175
|
-
|
|
220
|
+
```sh
|
|
221
|
+
bun run test:real
|
|
222
|
+
bun run test:real -- --keep-test-data # 保留临时数据以便手动检查
|
|
176
223
|
```
|
|
177
224
|
|
|
178
|
-
|
|
225
|
+
测试会优先读取 `.env.local`,如果不存在则读取 `env.local`。支持的环境变量:
|
|
226
|
+
|
|
227
|
+
| 变量 | 说明 | 默认值 |
|
|
228
|
+
|------|------|--------|
|
|
229
|
+
| `ZENTAO_URL` | 禅道站点地址 | *(必填)* |
|
|
230
|
+
| `ZENTAO_ACCOUNT` | 登录账号 | *(必填)* |
|
|
231
|
+
| `ZENTAO_PASSWORD` | 登录密码 | *(必填)* |
|
|
232
|
+
| `ZENTAO_TOKEN` | 直接提供 Token(替代账号密码) | — |
|
|
233
|
+
| `ZENTAO_REVIEWER` | 需求评审人(未设置时复用 `ZENTAO_ACCOUNT`) | — |
|
|
234
|
+
| `ZENTAO_KEEP_TEST_DATA` | 保留临时测试数据 | `false` |
|
|
235
|
+
| `ZENTAO_TIMEOUT` | 请求超时(ms) | `30000` |
|
|
236
|
+
| `ZENTAO_INSECURE` | 跳过 TLS 证书验证 | `false` |
|
|
179
237
|
|
|
180
|
-
|
|
181
|
-
|
|
238
|
+
## 项目结构
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
zentao-api/
|
|
242
|
+
├── src/
|
|
243
|
+
│ ├── client/ # ZentaoClient 核心实现
|
|
244
|
+
│ ├── modules/ # 模块注册表与解析逻辑
|
|
245
|
+
│ │ ├── generated.ts # 自动生成,勿手动编辑
|
|
246
|
+
│ │ ├── registry.ts # 运行时注册表
|
|
247
|
+
│ │ └── resolve.ts # 路径模板与参数解析
|
|
248
|
+
│ ├── request/ # 高阶请求函数
|
|
249
|
+
│ ├── profiles/ # 本地 profile 持久化
|
|
250
|
+
│ ├── misc/ # 错误、全局选项、环境检测
|
|
251
|
+
│ ├── types/ # TypeScript 类型定义
|
|
252
|
+
│ ├── utils/ # 通用工具函数
|
|
253
|
+
│ └── index.ts # 公共 API 入口
|
|
254
|
+
├── scripts/ # 构建与代码生成脚本
|
|
255
|
+
├── tests/ # 单元测试与真实环境测试
|
|
256
|
+
├── data/ # OpenAPI 规范文件
|
|
257
|
+
└── dist/ # 构建产物
|
|
182
258
|
```
|
|
183
259
|
|
|
184
|
-
|
|
260
|
+
## 贡献
|
|
185
261
|
|
|
186
|
-
|
|
262
|
+
欢迎贡献代码!请确保提交前通过完整检查:
|
|
187
263
|
|
|
188
|
-
```
|
|
189
|
-
|
|
264
|
+
```sh
|
|
265
|
+
bun run check
|
|
190
266
|
```
|
|
267
|
+
|
|
268
|
+
### 提交规范
|
|
269
|
+
|
|
270
|
+
使用英文,前缀格式:`*|+|- <type>: <message>`
|
|
271
|
+
|
|
272
|
+
- `*` — 修改 (change)
|
|
273
|
+
- `+` — 新增 (add)
|
|
274
|
+
- `-` — 移除 (remove)
|
|
275
|
+
|
|
276
|
+
不使用 emoji。
|
|
277
|
+
|
|
278
|
+
## 许可证 / License
|
|
279
|
+
|
|
280
|
+
[MIT](./LICENSE)
|