@ahoo-wang/fetcher 0.1.6 → 0.2.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/README.md +36 -34
- package/README.zh-CN.md +260 -0
- package/dist/fetcher.d.ts +64 -45
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/index.es.js +160 -150
- package/dist/index.umd.js +1 -1
- package/dist/interceptor.d.ts +18 -40
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/requestBodyInterceptor.d.ts +4 -5
- package/dist/requestBodyInterceptor.d.ts.map +1 -1
- package/dist/timeout.d.ts +3 -4
- package/dist/timeout.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
4
4
|
[](https://github.com/Ahoo-Wang/fetcher/actions)
|
|
5
|
-
[](https://codecov.io/gh/Ahoo-Wang/fetcher)
|
|
6
6
|
[](https://github.com/Ahoo-Wang/fetcher/blob/main/LICENSE)
|
|
7
7
|
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
8
8
|
|
|
@@ -87,13 +87,16 @@ const fetcher = new Fetcher({ baseURL: 'https://api.example.com' });
|
|
|
87
87
|
|
|
88
88
|
// Add request interceptor
|
|
89
89
|
const requestInterceptorId = fetcher.interceptors.request.use({
|
|
90
|
-
intercept(
|
|
90
|
+
intercept(exchange) {
|
|
91
91
|
// Modify request configuration, e.g., add auth header
|
|
92
92
|
return {
|
|
93
|
-
...
|
|
94
|
-
|
|
95
|
-
...request
|
|
96
|
-
|
|
93
|
+
...exchange,
|
|
94
|
+
request: {
|
|
95
|
+
...exchange.request,
|
|
96
|
+
headers: {
|
|
97
|
+
...exchange.request.headers,
|
|
98
|
+
Authorization: 'Bearer token',
|
|
99
|
+
},
|
|
97
100
|
},
|
|
98
101
|
};
|
|
99
102
|
},
|
|
@@ -101,18 +104,18 @@ const requestInterceptorId = fetcher.interceptors.request.use({
|
|
|
101
104
|
|
|
102
105
|
// Add response interceptor
|
|
103
106
|
const responseInterceptorId = fetcher.interceptors.response.use({
|
|
104
|
-
intercept(
|
|
107
|
+
intercept(exchange) {
|
|
105
108
|
// Process response data, e.g., parse JSON
|
|
106
|
-
return
|
|
109
|
+
return exchange;
|
|
107
110
|
},
|
|
108
111
|
});
|
|
109
112
|
|
|
110
113
|
// Add error interceptor
|
|
111
114
|
const errorInterceptorId = fetcher.interceptors.error.use({
|
|
112
|
-
intercept(
|
|
115
|
+
intercept(exchange) {
|
|
113
116
|
// Handle errors, e.g., log them
|
|
114
|
-
console.error('Request failed:', error);
|
|
115
|
-
return
|
|
117
|
+
console.error('Request failed:', exchange.error);
|
|
118
|
+
return exchange;
|
|
116
119
|
},
|
|
117
120
|
});
|
|
118
121
|
```
|
|
@@ -160,10 +163,10 @@ Interceptor manager for managing multiple interceptors of the same type.
|
|
|
160
163
|
|
|
161
164
|
#### Methods
|
|
162
165
|
|
|
163
|
-
- `use(interceptor:
|
|
166
|
+
- `use(interceptor: Interceptor): number` - Add interceptor, returns interceptor ID
|
|
164
167
|
- `eject(index: number): void` - Remove interceptor by ID
|
|
165
168
|
- `clear(): void` - Clear all interceptors
|
|
166
|
-
- `intercept(
|
|
169
|
+
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - Execute all interceptors sequentially
|
|
167
170
|
|
|
168
171
|
### FetcherInterceptors Class
|
|
169
172
|
|
|
@@ -171,9 +174,9 @@ Fetcher interceptor collection, including request, response, and error intercept
|
|
|
171
174
|
|
|
172
175
|
#### Properties
|
|
173
176
|
|
|
174
|
-
- `request:
|
|
175
|
-
- `response:
|
|
176
|
-
- `error:
|
|
177
|
+
- `request: InterceptorManager` - Request interceptor manager
|
|
178
|
+
- `response: InterceptorManager` - Response interceptor manager
|
|
179
|
+
- `error: InterceptorManager` - Error interceptor manager
|
|
177
180
|
|
|
178
181
|
## Complete Example
|
|
179
182
|
|
|
@@ -191,38 +194,37 @@ const fetcher = new Fetcher({
|
|
|
191
194
|
|
|
192
195
|
// Add request interceptor - Add auth header
|
|
193
196
|
fetcher.interceptors.request.use({
|
|
194
|
-
intercept(
|
|
197
|
+
intercept(exchange) {
|
|
195
198
|
return {
|
|
196
|
-
...
|
|
197
|
-
|
|
198
|
-
...request
|
|
199
|
-
|
|
199
|
+
...exchange,
|
|
200
|
+
request: {
|
|
201
|
+
...exchange.request,
|
|
202
|
+
headers: {
|
|
203
|
+
...exchange.request.headers,
|
|
204
|
+
Authorization: 'Bearer ' + getAuthToken(),
|
|
205
|
+
},
|
|
200
206
|
},
|
|
201
207
|
};
|
|
202
208
|
},
|
|
203
209
|
});
|
|
204
210
|
|
|
205
|
-
// Add response interceptor -
|
|
211
|
+
// Add response interceptor - Process response
|
|
206
212
|
fetcher.interceptors.response.use({
|
|
207
|
-
intercept(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return new Response(JSON.stringify(data), response);
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
return response;
|
|
213
|
+
intercept(exchange) {
|
|
214
|
+
// Note: Response processing would typically happen after the response is received
|
|
215
|
+
return exchange;
|
|
214
216
|
},
|
|
215
217
|
});
|
|
216
218
|
|
|
217
219
|
// Add error interceptor - Unified error handling
|
|
218
220
|
fetcher.interceptors.error.use({
|
|
219
|
-
intercept(
|
|
220
|
-
if (error
|
|
221
|
-
console.error('Request timeout:', error.message);
|
|
221
|
+
intercept(exchange) {
|
|
222
|
+
if (exchange.error?.name === 'FetchTimeoutError') {
|
|
223
|
+
console.error('Request timeout:', exchange.error.message);
|
|
222
224
|
} else {
|
|
223
|
-
console.error('Network error:', error
|
|
225
|
+
console.error('Network error:', exchange.error?.message);
|
|
224
226
|
}
|
|
225
|
-
return
|
|
227
|
+
return exchange;
|
|
226
228
|
},
|
|
227
229
|
});
|
|
228
230
|
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# @ahoo-wang/fetcher
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
4
|
+
[](https://github.com/Ahoo-Wang/fetcher/actions)
|
|
5
|
+
[](https://codecov.io/gh/Ahoo-Wang/fetcher)
|
|
6
|
+
[](https://github.com/Ahoo-Wang/fetcher/blob/main/LICENSE)
|
|
7
|
+
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
8
|
+
|
|
9
|
+
一个基于 Fetch API 的现代 HTTP 客户端库,旨在简化和优化与后端 RESTful API 的交互。它提供了类似 Axios 的 API,支持路径参数、查询参数、超时设置和请求/响应拦截器。
|
|
10
|
+
|
|
11
|
+
## 特性
|
|
12
|
+
|
|
13
|
+
- **Fetch API 兼容**:Fetcher 的 API 与原生 Fetch API 完全兼容,易于上手。
|
|
14
|
+
- **路径和查询参数**:支持请求中的路径参数和查询参数,路径参数用 `{}` 包装。
|
|
15
|
+
- **超时设置**:可以配置请求超时。
|
|
16
|
+
- **请求拦截器**:支持在发送请求前修改请求。
|
|
17
|
+
- **响应拦截器**:支持在返回响应后处理响应。
|
|
18
|
+
- **错误拦截器**:支持在请求生命周期中处理错误。
|
|
19
|
+
- **模块化设计**:代码结构清晰,易于维护和扩展。
|
|
20
|
+
- **自动请求体转换**:自动将普通对象转换为 JSON 并设置适当的 Content-Type 头部。
|
|
21
|
+
- **TypeScript 支持**:完整的 TypeScript 类型定义。
|
|
22
|
+
|
|
23
|
+
## 安装
|
|
24
|
+
|
|
25
|
+
使用 pnpm:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @ahoo-wang/fetcher
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
使用 npm:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @ahoo-wang/fetcher
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
使用 yarn:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
yarn add @ahoo-wang/fetcher
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 使用
|
|
44
|
+
|
|
45
|
+
### 基本用法
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
49
|
+
|
|
50
|
+
const fetcher = new Fetcher({
|
|
51
|
+
baseURL: 'https://api.example.com',
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// 带路径参数和查询参数的 GET 请求
|
|
56
|
+
fetcher
|
|
57
|
+
.get('/users/{id}', {
|
|
58
|
+
pathParams: { id: 123 },
|
|
59
|
+
queryParams: { include: 'profile' },
|
|
60
|
+
})
|
|
61
|
+
.then(response => {
|
|
62
|
+
console.log(response.data);
|
|
63
|
+
})
|
|
64
|
+
.catch(error => {
|
|
65
|
+
console.error(error);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// 带 JSON 体的 POST 请求(自动转换为 JSON 字符串)
|
|
69
|
+
fetcher
|
|
70
|
+
.post('/users', {
|
|
71
|
+
body: { name: 'John Doe', email: 'john@example.com' },
|
|
72
|
+
})
|
|
73
|
+
.then(response => {
|
|
74
|
+
console.log(response.data);
|
|
75
|
+
})
|
|
76
|
+
.catch(error => {
|
|
77
|
+
console.error(error);
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 拦截器用法
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
85
|
+
|
|
86
|
+
const fetcher = new Fetcher({ baseURL: 'https://api.example.com' });
|
|
87
|
+
|
|
88
|
+
// 添加请求拦截器
|
|
89
|
+
const requestInterceptorId = fetcher.interceptors.request.use({
|
|
90
|
+
intercept(exchange) {
|
|
91
|
+
// 修改请求配置,例如添加认证头部
|
|
92
|
+
return {
|
|
93
|
+
...exchange,
|
|
94
|
+
request: {
|
|
95
|
+
...exchange.request,
|
|
96
|
+
headers: {
|
|
97
|
+
...exchange.request.headers,
|
|
98
|
+
Authorization: 'Bearer token',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 添加响应拦截器
|
|
106
|
+
const responseInterceptorId = fetcher.interceptors.response.use({
|
|
107
|
+
intercept(exchange) {
|
|
108
|
+
// 处理响应数据,例如解析 JSON
|
|
109
|
+
return exchange;
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// 添加错误拦截器
|
|
114
|
+
const errorInterceptorId = fetcher.interceptors.error.use({
|
|
115
|
+
intercept(exchange) {
|
|
116
|
+
// 处理错误,例如记录日志
|
|
117
|
+
console.error('请求失败:', exchange.error);
|
|
118
|
+
return exchange;
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## API 参考
|
|
124
|
+
|
|
125
|
+
### Fetcher 类
|
|
126
|
+
|
|
127
|
+
提供各种 HTTP 方法的核心 HTTP 客户端类。
|
|
128
|
+
|
|
129
|
+
#### 构造函数
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
new Fetcher(options?: FetcherOptions)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**参数:**
|
|
136
|
+
|
|
137
|
+
- `options.baseURL`:基础 URL
|
|
138
|
+
- `options.timeout`:以毫秒为单位的请求超时
|
|
139
|
+
- `options.headers`:默认请求头部
|
|
140
|
+
|
|
141
|
+
#### 方法
|
|
142
|
+
|
|
143
|
+
- `fetch(url: string, request?: FetcherRequest): Promise<Response>` - 通用 HTTP 请求方法
|
|
144
|
+
- `get(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - GET 请求
|
|
145
|
+
- `post(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - POST 请求
|
|
146
|
+
- `put(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PUT 请求
|
|
147
|
+
- `delete(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - DELETE 请求
|
|
148
|
+
- `patch(url: string, request?: Omit<FetcherRequest, 'method'>): Promise<Response>` - PATCH 请求
|
|
149
|
+
- `head(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - HEAD 请求
|
|
150
|
+
- `options(url: string, request?: Omit<FetcherRequest, 'method' | 'body'>): Promise<Response>` - OPTIONS 请求
|
|
151
|
+
|
|
152
|
+
### UrlBuilder 类
|
|
153
|
+
|
|
154
|
+
用于构建带参数的完整 URL 的 URL 构建器。
|
|
155
|
+
|
|
156
|
+
#### 方法
|
|
157
|
+
|
|
158
|
+
- `build(path: string, pathParams?: Record<string, any>, queryParams?: Record<string, any>): string` - 构建完整 URL
|
|
159
|
+
|
|
160
|
+
### InterceptorManager 类
|
|
161
|
+
|
|
162
|
+
用于管理同一类型多个拦截器的拦截器管理器。
|
|
163
|
+
|
|
164
|
+
#### 方法
|
|
165
|
+
|
|
166
|
+
- `use(interceptor: Interceptor): number` - 添加拦截器,返回拦截器 ID
|
|
167
|
+
- `eject(index: number): void` - 按 ID 移除拦截器
|
|
168
|
+
- `clear(): void` - 清除所有拦截器
|
|
169
|
+
- `intercept(exchange: FetchExchange): Promise<FetchExchange>` - 顺序执行所有拦截器
|
|
170
|
+
|
|
171
|
+
### FetcherInterceptors 类
|
|
172
|
+
|
|
173
|
+
Fetcher 拦截器集合,包括请求、响应和错误拦截器管理器。
|
|
174
|
+
|
|
175
|
+
#### 属性
|
|
176
|
+
|
|
177
|
+
- `request: InterceptorManager` - 请求拦截器管理器
|
|
178
|
+
- `response: InterceptorManager` - 响应拦截器管理器
|
|
179
|
+
- `error: InterceptorManager` - 错误拦截器管理器
|
|
180
|
+
|
|
181
|
+
## 完整示例
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { Fetcher } from '@ahoo-wang/fetcher';
|
|
185
|
+
|
|
186
|
+
// 创建 fetcher 实例
|
|
187
|
+
const fetcher = new Fetcher({
|
|
188
|
+
baseURL: 'https://api.example.com',
|
|
189
|
+
timeout: 10000,
|
|
190
|
+
headers: {
|
|
191
|
+
'Content-Type': 'application/json',
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// 添加请求拦截器 - 添加认证头部
|
|
196
|
+
fetcher.interceptors.request.use({
|
|
197
|
+
intercept(exchange) {
|
|
198
|
+
return {
|
|
199
|
+
...exchange,
|
|
200
|
+
request: {
|
|
201
|
+
...exchange.request,
|
|
202
|
+
headers: {
|
|
203
|
+
...exchange.request.headers,
|
|
204
|
+
Authorization: 'Bearer ' + getAuthToken(),
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// 添加响应拦截器 - 处理响应
|
|
212
|
+
fetcher.interceptors.response.use({
|
|
213
|
+
intercept(exchange) {
|
|
214
|
+
// 注意:响应处理通常在收到响应后进行
|
|
215
|
+
return exchange;
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// 添加错误拦截器 - 统一错误处理
|
|
220
|
+
fetcher.interceptors.error.use({
|
|
221
|
+
intercept(exchange) {
|
|
222
|
+
if (exchange.error?.name === 'FetchTimeoutError') {
|
|
223
|
+
console.error('请求超时:', exchange.error.message);
|
|
224
|
+
} else {
|
|
225
|
+
console.error('网络错误:', exchange.error?.message);
|
|
226
|
+
}
|
|
227
|
+
return exchange;
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// 使用 fetcher 发起请求
|
|
232
|
+
fetcher
|
|
233
|
+
.get('/users/{id}', {
|
|
234
|
+
pathParams: { id: 123 },
|
|
235
|
+
queryParams: { include: 'profile,posts' },
|
|
236
|
+
})
|
|
237
|
+
.then(response => response.json())
|
|
238
|
+
.then(data => {
|
|
239
|
+
console.log('用户数据:', data);
|
|
240
|
+
})
|
|
241
|
+
.catch(error => {
|
|
242
|
+
console.error('获取用户失败:', error);
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## 测试
|
|
247
|
+
|
|
248
|
+
运行测试:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
pnpm test
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 贡献
|
|
255
|
+
|
|
256
|
+
欢迎任何形式的贡献!请查看 [贡献指南](https://github.com/Ahoo-Wang/fetcher/blob/main/CONTRIBUTING.md) 了解更多详情。
|
|
257
|
+
|
|
258
|
+
## 许可证
|
|
259
|
+
|
|
260
|
+
本项目采用 [Apache-2.0 许可证](https://opensource.org/licenses/Apache-2.0)。
|
package/dist/fetcher.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { TimeoutCapable } from './timeout';
|
|
2
2
|
import { BaseURLCapable, HeadersCapable, RequestField } from './types';
|
|
3
|
-
import { FetcherInterceptors } from './interceptor';
|
|
3
|
+
import { FetcherInterceptors, FetchExchange } from './interceptor';
|
|
4
4
|
/**
|
|
5
|
-
* Fetcher
|
|
5
|
+
* Fetcher configuration options interface
|
|
6
6
|
*/
|
|
7
7
|
export interface FetcherOptions extends BaseURLCapable, HeadersCapable, TimeoutCapable {
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Fetcher
|
|
10
|
+
* Fetcher request options interface
|
|
11
11
|
*/
|
|
12
12
|
export interface FetcherRequest extends TimeoutCapable, Omit<RequestInit, 'body'> {
|
|
13
13
|
pathParams?: Record<string, any>;
|
|
@@ -15,7 +15,7 @@ export interface FetcherRequest extends TimeoutCapable, Omit<RequestInit, 'body'
|
|
|
15
15
|
body?: BodyInit | Record<string, any> | null;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* HTTP
|
|
18
|
+
* HTTP client class that supports URL building, timeout control, and more
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* const fetcher = new Fetcher({ baseURL: 'https://api.example.com' });
|
|
@@ -31,85 +31,104 @@ export declare class Fetcher implements HeadersCapable, TimeoutCapable {
|
|
|
31
31
|
private urlBuilder;
|
|
32
32
|
interceptors: FetcherInterceptors;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Create a Fetcher instance
|
|
35
35
|
*
|
|
36
|
-
* @param options - Fetcher
|
|
36
|
+
* @param options - Fetcher configuration options
|
|
37
37
|
*/
|
|
38
38
|
constructor(options?: FetcherOptions);
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Make an HTTP request
|
|
41
41
|
*
|
|
42
|
-
* @param url -
|
|
43
|
-
* @param request -
|
|
44
|
-
* @returns Promise<Response> HTTP
|
|
42
|
+
* @param url - Request URL path
|
|
43
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
44
|
+
* @returns Promise<Response> HTTP response
|
|
45
45
|
*/
|
|
46
46
|
fetch(url: string, request?: FetcherRequest): Promise<Response>;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
48
|
+
* Send an HTTP request
|
|
49
49
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* @param url - Request URL address, supports path parameter placeholders
|
|
51
|
+
* @param request - Request configuration object, including method, headers, body, etc.
|
|
52
|
+
* @returns Promise that resolves to a FetchExchange object containing request and response information
|
|
52
53
|
*
|
|
53
|
-
* @
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
* @throws Throws an exception when an error occurs during the request and is not handled by error interceptors
|
|
55
|
+
*/
|
|
56
|
+
request(url: string, request?: FetcherRequest): Promise<FetchExchange>;
|
|
57
|
+
/**
|
|
58
|
+
* HTTP request method with timeout control
|
|
59
|
+
*
|
|
60
|
+
* This method uses Promise.race to implement timeout control, initiating both
|
|
61
|
+
* fetch request and timeout Promise simultaneously. When either Promise completes,
|
|
62
|
+
* it returns the result or throws an exception.
|
|
63
|
+
*
|
|
64
|
+
* @param exchange - The exchange containing request information
|
|
65
|
+
* @returns Promise<Response> HTTP response Promise
|
|
66
|
+
* @throws FetchTimeoutError Thrown when the request times out
|
|
57
67
|
*/
|
|
58
68
|
private timeoutFetch;
|
|
59
69
|
/**
|
|
60
|
-
*
|
|
70
|
+
* Make an HTTP request with the specified method
|
|
71
|
+
*
|
|
72
|
+
* @param method - HTTP method to use
|
|
73
|
+
* @param url - Request URL path
|
|
74
|
+
* @param request - Request options
|
|
75
|
+
* @returns Promise<Response> HTTP response
|
|
76
|
+
*/
|
|
77
|
+
private methodFetch;
|
|
78
|
+
/**
|
|
79
|
+
* Make a GET request
|
|
61
80
|
*
|
|
62
|
-
* @param url -
|
|
63
|
-
* @param request -
|
|
64
|
-
* @returns Promise<Response> HTTP
|
|
81
|
+
* @param url - Request URL path
|
|
82
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
83
|
+
* @returns Promise<Response> HTTP response
|
|
65
84
|
*/
|
|
66
85
|
get(url: string, request?: Omit<FetcherRequest, RequestField.METHOD | RequestField.BODY>): Promise<Response>;
|
|
67
86
|
/**
|
|
68
|
-
*
|
|
87
|
+
* Make a POST request
|
|
69
88
|
*
|
|
70
|
-
* @param url -
|
|
71
|
-
* @param request -
|
|
72
|
-
* @returns Promise<Response> HTTP
|
|
89
|
+
* @param url - Request URL path
|
|
90
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
91
|
+
* @returns Promise<Response> HTTP response
|
|
73
92
|
*/
|
|
74
93
|
post(url: string, request?: Omit<FetcherRequest, RequestField.METHOD>): Promise<Response>;
|
|
75
94
|
/**
|
|
76
|
-
*
|
|
95
|
+
* Make a PUT request
|
|
77
96
|
*
|
|
78
|
-
* @param url -
|
|
79
|
-
* @param request -
|
|
80
|
-
* @returns Promise<Response> HTTP
|
|
97
|
+
* @param url - Request URL path
|
|
98
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
99
|
+
* @returns Promise<Response> HTTP response
|
|
81
100
|
*/
|
|
82
101
|
put(url: string, request?: Omit<FetcherRequest, RequestField.METHOD>): Promise<Response>;
|
|
83
102
|
/**
|
|
84
|
-
*
|
|
103
|
+
* Make a DELETE request
|
|
85
104
|
*
|
|
86
|
-
* @param url -
|
|
87
|
-
* @param request -
|
|
88
|
-
* @returns Promise<Response> HTTP
|
|
105
|
+
* @param url - Request URL path
|
|
106
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
107
|
+
* @returns Promise<Response> HTTP response
|
|
89
108
|
*/
|
|
90
109
|
delete(url: string, request?: Omit<FetcherRequest, RequestField.METHOD>): Promise<Response>;
|
|
91
110
|
/**
|
|
92
|
-
*
|
|
111
|
+
* Make a PATCH request
|
|
93
112
|
*
|
|
94
|
-
* @param url -
|
|
95
|
-
* @param request -
|
|
96
|
-
* @returns Promise<Response> HTTP
|
|
113
|
+
* @param url - Request URL path
|
|
114
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
115
|
+
* @returns Promise<Response> HTTP response
|
|
97
116
|
*/
|
|
98
117
|
patch(url: string, request?: Omit<FetcherRequest, RequestField.METHOD>): Promise<Response>;
|
|
99
118
|
/**
|
|
100
|
-
*
|
|
119
|
+
* Make a HEAD request
|
|
101
120
|
*
|
|
102
|
-
* @param url -
|
|
103
|
-
* @param request -
|
|
104
|
-
* @returns Promise<Response> HTTP
|
|
121
|
+
* @param url - Request URL path
|
|
122
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
123
|
+
* @returns Promise<Response> HTTP response
|
|
105
124
|
*/
|
|
106
125
|
head(url: string, request?: Omit<FetcherRequest, RequestField.METHOD | RequestField.BODY>): Promise<Response>;
|
|
107
126
|
/**
|
|
108
|
-
*
|
|
127
|
+
* Make an OPTIONS request
|
|
109
128
|
*
|
|
110
|
-
* @param url -
|
|
111
|
-
* @param request -
|
|
112
|
-
* @returns Promise<Response> HTTP
|
|
129
|
+
* @param url - Request URL path
|
|
130
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
131
|
+
* @returns Promise<Response> HTTP response
|
|
113
132
|
*/
|
|
114
133
|
options(url: string, request?: Omit<FetcherRequest, RequestField.METHOD | RequestField.BODY>): Promise<Response>;
|
|
115
134
|
}
|
package/dist/fetcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAqC,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EACL,cAAc,EAGd,cAAc,EAEd,YAAY,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAqC,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EACL,cAAc,EAGd,cAAc,EAEd,YAAY,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnE;;GAEG;AACH,MAAM,WAAW,cACf,SAAQ,cAAc,EACpB,cAAc,EACd,cAAc;CACjB;AAWD;;GAEG;AACH,MAAM,WAAW,cACf,SAAQ,cAAc,EACpB,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED;;;;;;;;;;GAUG;AACH,qBAAa,OAAQ,YAAW,cAAc,EAAE,cAAc;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAkB;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,UAAU,CAAa;IAC/B,YAAY,EAAE,mBAAmB,CAA6B;IAE9D;;;;OAIG;gBACS,OAAO,GAAE,cAA+B;IASpD;;;;;;OAMG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQzE;;;;;;;;OAQG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC;IA0CzB;;;;;;;;;;OAUG;YACW,YAAY;IA2C1B;;;;;;;OAOG;YACW,WAAW;IAWzB;;;;;;OAMG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAM,GAC1E,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,IAAI,CACR,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,KAAK,CACT,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,IAAI,CACR,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAM,GAC1E,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;OAMG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAM,GAC1E,OAAO,CAAC,QAAQ,CAAC;CAGrB"}
|
package/dist/index.es.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function
|
|
1
|
+
function b(r) {
|
|
2
2
|
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(r);
|
|
3
3
|
}
|
|
4
|
-
function
|
|
5
|
-
return
|
|
4
|
+
function E(r, e) {
|
|
5
|
+
return b(e) ? e : e ? r.replace(/\/?\/$/, "") + "/" + e.replace(/^\/+/, "") : r;
|
|
6
6
|
}
|
|
7
|
-
class
|
|
7
|
+
class w {
|
|
8
8
|
/**
|
|
9
9
|
* 创建UrlBuilder实例
|
|
10
10
|
*
|
|
@@ -22,13 +22,13 @@ class E {
|
|
|
22
22
|
* @returns 完整的URL字符串
|
|
23
23
|
* @throws 当路径参数中缺少必需的占位符时抛出错误
|
|
24
24
|
*/
|
|
25
|
-
build(e, t,
|
|
26
|
-
let
|
|
27
|
-
if (
|
|
28
|
-
const
|
|
29
|
-
|
|
25
|
+
build(e, t, s) {
|
|
26
|
+
let o = E(this.baseURL, e), i = this.interpolateUrl(o, t);
|
|
27
|
+
if (s) {
|
|
28
|
+
const n = new URLSearchParams(s).toString();
|
|
29
|
+
n && (i += "?" + n);
|
|
30
30
|
}
|
|
31
|
-
return
|
|
31
|
+
return i;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* 替换url中的占位符参数
|
|
@@ -39,26 +39,26 @@ class E {
|
|
|
39
39
|
* @throws 当路径参数中缺少必需的占位符时抛出错误
|
|
40
40
|
*/
|
|
41
41
|
interpolateUrl(e, t) {
|
|
42
|
-
return t ? e.replace(/{([^}]+)}/g, (
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
throw new Error(`Missing required path parameter: ${
|
|
46
|
-
return String(
|
|
42
|
+
return t ? e.replace(/{([^}]+)}/g, (s, o) => {
|
|
43
|
+
const i = t[o];
|
|
44
|
+
if (i === void 0)
|
|
45
|
+
throw new Error(`Missing required path parameter: ${o}`);
|
|
46
|
+
return String(i);
|
|
47
47
|
}) : e;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
function P(r, e) {
|
|
51
51
|
return typeof r < "u" ? r : e;
|
|
52
52
|
}
|
|
53
|
-
class
|
|
54
|
-
constructor(e, t
|
|
55
|
-
const s = `Request timeout of ${
|
|
56
|
-
super(
|
|
53
|
+
class l extends Error {
|
|
54
|
+
constructor(e, t) {
|
|
55
|
+
const s = e.request?.method || "GET", o = `Request timeout of ${t}ms exceeded for ${s} ${e.url}`;
|
|
56
|
+
super(o), this.name = "FetchTimeoutError", this.exchange = e, Object.setPrototypeOf(this, l.prototype);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
var c = /* @__PURE__ */ ((r) => (r.GET = "GET", r.POST = "POST", r.PUT = "PUT", r.DELETE = "DELETE", r.PATCH = "PATCH", r.HEAD = "HEAD", r.OPTIONS = "OPTIONS", r))(c || {}), O = /* @__PURE__ */ ((r) => (r.METHOD = "method", r.BODY = "body", r))(O || {});
|
|
60
60
|
const d = "Content-Type";
|
|
61
|
-
var
|
|
61
|
+
var f = /* @__PURE__ */ ((r) => (r.APPLICATION_JSON = "application/json", r.TEXT_EVENT_STREAM = "text/event-stream", r))(f || {});
|
|
62
62
|
class h {
|
|
63
63
|
constructor() {
|
|
64
64
|
this.interceptors = [];
|
|
@@ -87,22 +87,22 @@ class h {
|
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
89
|
* 依次执行所有拦截器对数据的处理
|
|
90
|
-
* @param
|
|
90
|
+
* @param exchange - 需要处理的数据
|
|
91
91
|
* @returns 经过所有拦截器处理后的数据
|
|
92
92
|
*/
|
|
93
93
|
async intercept(e) {
|
|
94
94
|
let t = e;
|
|
95
|
-
for (let
|
|
96
|
-
|
|
95
|
+
for (let s of this.interceptors)
|
|
96
|
+
s && (t = await s.intercept(t));
|
|
97
97
|
return t;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
class
|
|
100
|
+
class A {
|
|
101
101
|
constructor() {
|
|
102
102
|
this.request = new h(), this.response = new h(), this.error = new h();
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
class
|
|
105
|
+
class S {
|
|
106
106
|
/**
|
|
107
107
|
* 尝试转换请求体为合法的 fetch API body 类型
|
|
108
108
|
*
|
|
@@ -122,206 +122,216 @@ class A {
|
|
|
122
122
|
*
|
|
123
123
|
* 对于不支持的 object 类型(如普通对象),将自动转换为 JSON 字符串
|
|
124
124
|
*
|
|
125
|
-
* @param
|
|
125
|
+
* @param exchange
|
|
126
126
|
* @returns 转换后的请求
|
|
127
127
|
*/
|
|
128
128
|
intercept(e) {
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const t = e.request;
|
|
130
|
+
if (t.body === void 0 || t.body === null || typeof t.body != "object" || t.body instanceof ArrayBuffer || ArrayBuffer.isView(t.body) || // 包括 TypedArray 和 DataView
|
|
131
|
+
t.body instanceof Blob || t.body instanceof File || t.body instanceof URLSearchParams || t.body instanceof FormData || t.body instanceof ReadableStream)
|
|
131
132
|
return e;
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
return
|
|
133
|
+
const s = { ...t };
|
|
134
|
+
s.body = JSON.stringify(t.body), s.headers || (s.headers = {});
|
|
135
|
+
const o = s.headers;
|
|
136
|
+
return o[d] || (o[d] = f.APPLICATION_JSON), { ...e, request: s };
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
|
-
const
|
|
139
|
-
[d]:
|
|
140
|
-
},
|
|
139
|
+
const m = {
|
|
140
|
+
[d]: f.APPLICATION_JSON
|
|
141
|
+
}, q = {
|
|
141
142
|
baseURL: "",
|
|
142
|
-
headers:
|
|
143
|
+
headers: m
|
|
143
144
|
};
|
|
144
145
|
class I {
|
|
145
146
|
/**
|
|
146
|
-
*
|
|
147
|
+
* Create a Fetcher instance
|
|
147
148
|
*
|
|
148
|
-
* @param options - Fetcher
|
|
149
|
+
* @param options - Fetcher configuration options
|
|
149
150
|
*/
|
|
150
|
-
constructor(e =
|
|
151
|
-
this.headers =
|
|
151
|
+
constructor(e = q) {
|
|
152
|
+
this.headers = m, this.interceptors = new A(), this.urlBuilder = new w(e.baseURL), e.headers !== void 0 && (this.headers = e.headers), this.timeout = e.timeout, this.interceptors.request.use(new S());
|
|
152
153
|
}
|
|
153
154
|
/**
|
|
154
|
-
*
|
|
155
|
+
* Make an HTTP request
|
|
155
156
|
*
|
|
156
|
-
* @param url -
|
|
157
|
-
* @param request -
|
|
158
|
-
* @returns Promise<Response> HTTP
|
|
157
|
+
* @param url - Request URL path
|
|
158
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
159
|
+
* @returns Promise<Response> HTTP response
|
|
159
160
|
*/
|
|
160
161
|
async fetch(e, t = {}) {
|
|
161
|
-
const
|
|
162
|
+
const s = await this.request(e, t);
|
|
163
|
+
if (!s.response)
|
|
164
|
+
throw new Error(`Request to ${s.url} failed with no response`);
|
|
165
|
+
return s.response;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Send an HTTP request
|
|
169
|
+
*
|
|
170
|
+
* @param url - Request URL address, supports path parameter placeholders
|
|
171
|
+
* @param request - Request configuration object, including method, headers, body, etc.
|
|
172
|
+
* @returns Promise that resolves to a FetchExchange object containing request and response information
|
|
173
|
+
*
|
|
174
|
+
* @throws Throws an exception when an error occurs during the request and is not handled by error interceptors
|
|
175
|
+
*/
|
|
176
|
+
async request(e, t = {}) {
|
|
177
|
+
const s = {
|
|
162
178
|
...this.headers || {},
|
|
163
179
|
...t.headers || {}
|
|
164
|
-
}
|
|
165
|
-
let s = {
|
|
180
|
+
}, o = {
|
|
166
181
|
...t,
|
|
167
|
-
headers: Object.keys(
|
|
182
|
+
headers: Object.keys(s).length > 0 ? s : void 0
|
|
183
|
+
}, i = this.urlBuilder.build(
|
|
184
|
+
e,
|
|
185
|
+
t.pathParams,
|
|
186
|
+
t.queryParams
|
|
187
|
+
);
|
|
188
|
+
let n = {
|
|
189
|
+
fetcher: this,
|
|
190
|
+
url: i,
|
|
191
|
+
request: o,
|
|
192
|
+
response: void 0,
|
|
193
|
+
error: void 0
|
|
168
194
|
};
|
|
169
195
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
), a = {
|
|
176
|
-
...s,
|
|
177
|
-
body: s.body
|
|
178
|
-
};
|
|
179
|
-
let i = await this.timeoutFetch(o, a);
|
|
180
|
-
return i = await this.interceptors.response.intercept(i), i;
|
|
181
|
-
} catch (o) {
|
|
182
|
-
throw await this.interceptors.error.intercept(o);
|
|
196
|
+
return n = await this.interceptors.request.intercept(n), n.response = await this.timeoutFetch(n), n = await this.interceptors.response.intercept(n), n;
|
|
197
|
+
} catch (u) {
|
|
198
|
+
if (n.error = u, n = await this.interceptors.error.intercept(n), n.response)
|
|
199
|
+
return n;
|
|
200
|
+
throw n.error;
|
|
183
201
|
}
|
|
184
202
|
}
|
|
185
203
|
/**
|
|
186
|
-
*
|
|
204
|
+
* HTTP request method with timeout control
|
|
187
205
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
206
|
+
* This method uses Promise.race to implement timeout control, initiating both
|
|
207
|
+
* fetch request and timeout Promise simultaneously. When either Promise completes,
|
|
208
|
+
* it returns the result or throws an exception.
|
|
190
209
|
*
|
|
191
|
-
* @param
|
|
192
|
-
* @
|
|
193
|
-
* @
|
|
194
|
-
* @throws FetchTimeoutError 当请求超时时抛出
|
|
210
|
+
* @param exchange - The exchange containing request information
|
|
211
|
+
* @returns Promise<Response> HTTP response Promise
|
|
212
|
+
* @throws FetchTimeoutError Thrown when the request times out
|
|
195
213
|
*/
|
|
196
|
-
async timeoutFetch(e
|
|
197
|
-
const
|
|
198
|
-
if (!
|
|
199
|
-
return fetch(
|
|
200
|
-
const
|
|
201
|
-
...
|
|
202
|
-
signal:
|
|
214
|
+
async timeoutFetch(e) {
|
|
215
|
+
const t = e.url, s = e.request, o = s.timeout, i = P(o, this.timeout);
|
|
216
|
+
if (!i)
|
|
217
|
+
return fetch(t, s);
|
|
218
|
+
const n = new AbortController(), u = {
|
|
219
|
+
...s,
|
|
220
|
+
signal: n.signal
|
|
203
221
|
};
|
|
204
|
-
let
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
s
|
|
212
|
-
);
|
|
213
|
-
o.abort(l), y(l);
|
|
214
|
-
}, s);
|
|
222
|
+
let a = null;
|
|
223
|
+
const y = new Promise((F, T) => {
|
|
224
|
+
a = setTimeout(() => {
|
|
225
|
+
a && clearTimeout(a);
|
|
226
|
+
const p = new l(e, i);
|
|
227
|
+
n.abort(p), T(p);
|
|
228
|
+
}, i);
|
|
215
229
|
});
|
|
216
230
|
try {
|
|
217
|
-
return await Promise.race([
|
|
231
|
+
return await Promise.race([
|
|
232
|
+
fetch(t, u),
|
|
233
|
+
y
|
|
234
|
+
]);
|
|
218
235
|
} finally {
|
|
219
|
-
|
|
236
|
+
a && clearTimeout(a);
|
|
220
237
|
}
|
|
221
238
|
}
|
|
222
239
|
/**
|
|
223
|
-
*
|
|
240
|
+
* Make an HTTP request with the specified method
|
|
224
241
|
*
|
|
225
|
-
* @param
|
|
226
|
-
* @param
|
|
227
|
-
* @
|
|
242
|
+
* @param method - HTTP method to use
|
|
243
|
+
* @param url - Request URL path
|
|
244
|
+
* @param request - Request options
|
|
245
|
+
* @returns Promise<Response> HTTP response
|
|
228
246
|
*/
|
|
229
|
-
async
|
|
230
|
-
return this.fetch(
|
|
231
|
-
...
|
|
232
|
-
method:
|
|
247
|
+
async methodFetch(e, t, s = {}) {
|
|
248
|
+
return this.fetch(t, {
|
|
249
|
+
...s,
|
|
250
|
+
method: e
|
|
233
251
|
});
|
|
234
252
|
}
|
|
235
253
|
/**
|
|
236
|
-
*
|
|
254
|
+
* Make a GET request
|
|
255
|
+
*
|
|
256
|
+
* @param url - Request URL path
|
|
257
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
258
|
+
* @returns Promise<Response> HTTP response
|
|
259
|
+
*/
|
|
260
|
+
async get(e, t = {}) {
|
|
261
|
+
return this.methodFetch(c.GET, e, t);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Make a POST request
|
|
237
265
|
*
|
|
238
|
-
* @param url -
|
|
239
|
-
* @param request -
|
|
240
|
-
* @returns Promise<Response> HTTP
|
|
266
|
+
* @param url - Request URL path
|
|
267
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
268
|
+
* @returns Promise<Response> HTTP response
|
|
241
269
|
*/
|
|
242
270
|
async post(e, t = {}) {
|
|
243
|
-
return this.
|
|
244
|
-
...t,
|
|
245
|
-
method: c.POST
|
|
246
|
-
});
|
|
271
|
+
return this.methodFetch(c.POST, e, t);
|
|
247
272
|
}
|
|
248
273
|
/**
|
|
249
|
-
*
|
|
274
|
+
* Make a PUT request
|
|
250
275
|
*
|
|
251
|
-
* @param url -
|
|
252
|
-
* @param request -
|
|
253
|
-
* @returns Promise<Response> HTTP
|
|
276
|
+
* @param url - Request URL path
|
|
277
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
278
|
+
* @returns Promise<Response> HTTP response
|
|
254
279
|
*/
|
|
255
280
|
async put(e, t = {}) {
|
|
256
|
-
return this.
|
|
257
|
-
...t,
|
|
258
|
-
method: c.PUT
|
|
259
|
-
});
|
|
281
|
+
return this.methodFetch(c.PUT, e, t);
|
|
260
282
|
}
|
|
261
283
|
/**
|
|
262
|
-
*
|
|
284
|
+
* Make a DELETE request
|
|
263
285
|
*
|
|
264
|
-
* @param url -
|
|
265
|
-
* @param request -
|
|
266
|
-
* @returns Promise<Response> HTTP
|
|
286
|
+
* @param url - Request URL path
|
|
287
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
288
|
+
* @returns Promise<Response> HTTP response
|
|
267
289
|
*/
|
|
268
290
|
async delete(e, t = {}) {
|
|
269
|
-
return this.
|
|
270
|
-
...t,
|
|
271
|
-
method: c.DELETE
|
|
272
|
-
});
|
|
291
|
+
return this.methodFetch(c.DELETE, e, t);
|
|
273
292
|
}
|
|
274
293
|
/**
|
|
275
|
-
*
|
|
294
|
+
* Make a PATCH request
|
|
276
295
|
*
|
|
277
|
-
* @param url -
|
|
278
|
-
* @param request -
|
|
279
|
-
* @returns Promise<Response> HTTP
|
|
296
|
+
* @param url - Request URL path
|
|
297
|
+
* @param request - Request options, including path parameters, query parameters, request body, etc.
|
|
298
|
+
* @returns Promise<Response> HTTP response
|
|
280
299
|
*/
|
|
281
300
|
async patch(e, t = {}) {
|
|
282
|
-
return this.
|
|
283
|
-
...t,
|
|
284
|
-
method: c.PATCH
|
|
285
|
-
});
|
|
301
|
+
return this.methodFetch(c.PATCH, e, t);
|
|
286
302
|
}
|
|
287
303
|
/**
|
|
288
|
-
*
|
|
304
|
+
* Make a HEAD request
|
|
289
305
|
*
|
|
290
|
-
* @param url -
|
|
291
|
-
* @param request -
|
|
292
|
-
* @returns Promise<Response> HTTP
|
|
306
|
+
* @param url - Request URL path
|
|
307
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
308
|
+
* @returns Promise<Response> HTTP response
|
|
293
309
|
*/
|
|
294
310
|
async head(e, t = {}) {
|
|
295
|
-
return this.
|
|
296
|
-
...t,
|
|
297
|
-
method: c.HEAD
|
|
298
|
-
});
|
|
311
|
+
return this.methodFetch(c.HEAD, e, t);
|
|
299
312
|
}
|
|
300
313
|
/**
|
|
301
|
-
*
|
|
314
|
+
* Make an OPTIONS request
|
|
302
315
|
*
|
|
303
|
-
* @param url -
|
|
304
|
-
* @param request -
|
|
305
|
-
* @returns Promise<Response> HTTP
|
|
316
|
+
* @param url - Request URL path
|
|
317
|
+
* @param request - Request options, including path parameters, query parameters, etc.
|
|
318
|
+
* @returns Promise<Response> HTTP response
|
|
306
319
|
*/
|
|
307
320
|
async options(e, t = {}) {
|
|
308
|
-
return this.
|
|
309
|
-
...t,
|
|
310
|
-
method: c.OPTIONS
|
|
311
|
-
});
|
|
321
|
+
return this.methodFetch(c.OPTIONS, e, t);
|
|
312
322
|
}
|
|
313
323
|
}
|
|
314
324
|
export {
|
|
315
325
|
d as ContentTypeHeader,
|
|
316
|
-
|
|
317
|
-
|
|
326
|
+
f as ContentTypeValues,
|
|
327
|
+
l as FetchTimeoutError,
|
|
318
328
|
I as Fetcher,
|
|
319
|
-
|
|
329
|
+
A as FetcherInterceptors,
|
|
320
330
|
c as HttpMethod,
|
|
321
331
|
h as InterceptorManager,
|
|
322
332
|
O as RequestField,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
333
|
+
w as UrlBuilder,
|
|
334
|
+
E as combineURLs,
|
|
335
|
+
b as isAbsoluteURL,
|
|
326
336
|
P as resolveTimeout
|
|
327
337
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(i,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(i=typeof globalThis<"u"?globalThis:i||self,a(i.Fetcher={}))})(this,(function(i){"use strict";function a(r){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(r)}function y(r,e){return a(e)?e:e?r.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):r}class T{constructor(e){this.baseURL=e}build(e,t,s){let o=y(this.baseURL,e),c=this.interpolateUrl(o,t);if(s){const n=new URLSearchParams(s).toString();n&&(c+="?"+n)}return c}interpolateUrl(e,t){return t?e.replace(/{([^}]+)}/g,(s,o)=>{const c=t[o];if(c===void 0)throw new Error(`Missing required path parameter: ${o}`);return String(c)}):e}}function b(r,e){return typeof r<"u"?r:e}class d extends Error{constructor(e,t){const s=e.request?.method||"GET",o=`Request timeout of ${t}ms exceeded for ${s} ${e.url}`;super(o),this.name="FetchTimeoutError",this.exchange=e,Object.setPrototypeOf(this,d.prototype)}}var u=(r=>(r.GET="GET",r.POST="POST",r.PUT="PUT",r.DELETE="DELETE",r.PATCH="PATCH",r.HEAD="HEAD",r.OPTIONS="OPTIONS",r))(u||{}),E=(r=>(r.METHOD="method",r.BODY="body",r))(E||{});const l="Content-Type";var f=(r=>(r.APPLICATION_JSON="application/json",r.TEXT_EVENT_STREAM="text/event-stream",r))(f||{});class m{constructor(){this.interceptors=[]}use(e){const t=this.interceptors.length;return this.interceptors.push(e),t}eject(e){this.interceptors[e]&&(this.interceptors[e]=null)}clear(){this.interceptors=[]}async intercept(e){let t=e;for(let s of this.interceptors)s&&(t=await s.intercept(t));return t}}class P{constructor(){this.request=new m,this.response=new m,this.error=new m}}class F{intercept(e){const t=e.request;if(t.body===void 0||t.body===null||typeof t.body!="object"||t.body instanceof ArrayBuffer||ArrayBuffer.isView(t.body)||t.body instanceof Blob||t.body instanceof File||t.body instanceof URLSearchParams||t.body instanceof FormData||t.body instanceof ReadableStream)return e;const s={...t};s.body=JSON.stringify(t.body),s.headers||(s.headers={});const o=s.headers;return o[l]||(o[l]=f.APPLICATION_JSON),{...e,request:s}}}const w={[l]:f.APPLICATION_JSON},S={baseURL:"",headers:w};class A{constructor(e=S){this.headers=w,this.interceptors=new P,this.urlBuilder=new T(e.baseURL),e.headers!==void 0&&(this.headers=e.headers),this.timeout=e.timeout,this.interceptors.request.use(new F)}async fetch(e,t={}){const s=await this.request(e,t);if(!s.response)throw new Error(`Request to ${s.url} failed with no response`);return s.response}async request(e,t={}){const s={...this.headers||{},...t.headers||{}},o={...t,headers:Object.keys(s).length>0?s:void 0},c=this.urlBuilder.build(e,t.pathParams,t.queryParams);let n={fetcher:this,url:c,request:o,response:void 0,error:void 0};try{return n=await this.interceptors.request.intercept(n),n.response=await this.timeoutFetch(n),n=await this.interceptors.response.intercept(n),n}catch(p){if(n.error=p,n=await this.interceptors.error.intercept(n),n.response)return n;throw n.error}}async timeoutFetch(e){const t=e.url,s=e.request,o=s.timeout,c=b(o,this.timeout);if(!c)return fetch(t,s);const n=new AbortController,p={...s,signal:n.signal};let h=null;const q=new Promise((I,U)=>{h=setTimeout(()=>{h&&clearTimeout(h);const O=new d(e,c);n.abort(O),U(O)},c)});try{return await Promise.race([fetch(t,p),q])}finally{h&&clearTimeout(h)}}async methodFetch(e,t,s={}){return this.fetch(t,{...s,method:e})}async get(e,t={}){return this.methodFetch(u.GET,e,t)}async post(e,t={}){return this.methodFetch(u.POST,e,t)}async put(e,t={}){return this.methodFetch(u.PUT,e,t)}async delete(e,t={}){return this.methodFetch(u.DELETE,e,t)}async patch(e,t={}){return this.methodFetch(u.PATCH,e,t)}async head(e,t={}){return this.methodFetch(u.HEAD,e,t)}async options(e,t={}){return this.methodFetch(u.OPTIONS,e,t)}}i.ContentTypeHeader=l,i.ContentTypeValues=f,i.FetchTimeoutError=d,i.Fetcher=A,i.FetcherInterceptors=P,i.HttpMethod=u,i.InterceptorManager=m,i.RequestField=E,i.UrlBuilder=T,i.combineURLs=y,i.isAbsoluteURL=a,i.resolveTimeout=b,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/interceptor.d.ts
CHANGED
|
@@ -1,44 +1,34 @@
|
|
|
1
|
-
import { FetcherRequest } from './fetcher';
|
|
1
|
+
import { Fetcher, FetcherRequest } from './fetcher';
|
|
2
|
+
export interface FetchExchange {
|
|
3
|
+
fetcher: Fetcher;
|
|
4
|
+
url: string;
|
|
5
|
+
request: FetcherRequest;
|
|
6
|
+
response: Response | undefined;
|
|
7
|
+
error: Error | any | undefined;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* 拦截器接口,定义了拦截器的基本结构
|
|
4
11
|
* @template T - 拦截器处理的数据类型
|
|
5
12
|
*/
|
|
6
|
-
export interface Interceptor
|
|
13
|
+
export interface Interceptor {
|
|
7
14
|
/**
|
|
8
15
|
* 拦截并处理数据
|
|
9
|
-
* @param
|
|
16
|
+
* @param exchange - 需要处理的数据
|
|
10
17
|
* @returns 处理后的数据,可以是同步或异步返回
|
|
11
18
|
*/
|
|
12
|
-
intercept(
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* 请求拦截器接口,专门用于处理请求数据
|
|
16
|
-
*/
|
|
17
|
-
export interface RequestInterceptor extends Interceptor<FetcherRequest> {
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 响应拦截器接口,专门用于处理响应数据
|
|
21
|
-
*/
|
|
22
|
-
export interface ResponseInterceptor extends Interceptor<Response> {
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* 错误拦截器接口,专门用于处理错误数据
|
|
26
|
-
*/
|
|
27
|
-
export interface ErrorInterceptor extends Interceptor<any> {
|
|
19
|
+
intercept(exchange: FetchExchange): FetchExchange | Promise<FetchExchange>;
|
|
28
20
|
}
|
|
29
21
|
/**
|
|
30
22
|
* 拦截器管理器类,用于管理同一类型的多个拦截器
|
|
31
|
-
* @template R - 拦截器处理的数据类型
|
|
32
|
-
* @template T - 拦截器类型
|
|
33
23
|
*/
|
|
34
|
-
export declare class InterceptorManager
|
|
24
|
+
export declare class InterceptorManager implements Interceptor {
|
|
35
25
|
private interceptors;
|
|
36
26
|
/**
|
|
37
27
|
* 添加拦截器到管理器中
|
|
38
28
|
* @param interceptor - 要添加的拦截器
|
|
39
29
|
* @returns 拦截器在管理器中的索引位置
|
|
40
30
|
*/
|
|
41
|
-
use(interceptor:
|
|
31
|
+
use(interceptor: Interceptor): number;
|
|
42
32
|
/**
|
|
43
33
|
* 根据索引移除拦截器
|
|
44
34
|
* @param index - 要移除的拦截器索引
|
|
@@ -50,23 +40,11 @@ export declare class InterceptorManager<R, T extends Interceptor<R>> implements
|
|
|
50
40
|
clear(): void;
|
|
51
41
|
/**
|
|
52
42
|
* 依次执行所有拦截器对数据的处理
|
|
53
|
-
* @param
|
|
43
|
+
* @param exchange - 需要处理的数据
|
|
54
44
|
* @returns 经过所有拦截器处理后的数据
|
|
55
45
|
*/
|
|
56
|
-
intercept(
|
|
46
|
+
intercept(exchange: FetchExchange): Promise<FetchExchange>;
|
|
57
47
|
}
|
|
58
|
-
/**
|
|
59
|
-
* 请求拦截器管理器类型定义
|
|
60
|
-
*/
|
|
61
|
-
export type RequestInterceptorManager = InterceptorManager<FetcherRequest, RequestInterceptor>;
|
|
62
|
-
/**
|
|
63
|
-
* 响应拦截器管理器类型定义
|
|
64
|
-
*/
|
|
65
|
-
export type ResponseInterceptorManager = InterceptorManager<Response, ResponseInterceptor>;
|
|
66
|
-
/**
|
|
67
|
-
* 错误拦截器管理器类型定义
|
|
68
|
-
*/
|
|
69
|
-
export type ErrorInterceptorManager = InterceptorManager<any, ErrorInterceptor>;
|
|
70
48
|
/**
|
|
71
49
|
* Fetcher拦截器集合类,包含请求、响应和错误拦截器管理器
|
|
72
50
|
*/
|
|
@@ -74,14 +52,14 @@ export declare class FetcherInterceptors {
|
|
|
74
52
|
/**
|
|
75
53
|
* 请求拦截器管理器
|
|
76
54
|
*/
|
|
77
|
-
request:
|
|
55
|
+
request: InterceptorManager;
|
|
78
56
|
/**
|
|
79
57
|
* 响应拦截器管理器
|
|
80
58
|
*/
|
|
81
|
-
response:
|
|
59
|
+
response: InterceptorManager;
|
|
82
60
|
/**
|
|
83
61
|
* 错误拦截器管理器
|
|
84
62
|
*/
|
|
85
|
-
error:
|
|
63
|
+
error: InterceptorManager;
|
|
86
64
|
}
|
|
87
65
|
//# sourceMappingURL=interceptor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC/B,KAAK,EAAE,KAAK,GAAG,GAAG,GAAG,SAAS,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC5E;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IACpD,OAAO,CAAC,YAAY,CAAiC;IAErD;;;;OAIG;IACH,GAAG,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM;IAMrC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;;OAIG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAUjE;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACH,OAAO,EAAE,kBAAkB,CAA4B;IAEvD;;OAEG;IACH,QAAQ,EAAE,kBAAkB,CAA4B;IAExD;;OAEG;IACH,KAAK,EAAE,kBAAkB,CAA4B;CACtD"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FetcherRequest } from './fetcher';
|
|
1
|
+
import { FetchExchange, Interceptor } from './interceptor';
|
|
3
2
|
/**
|
|
4
3
|
* 请求体拦截器,负责将普通对象转换为JSON字符串
|
|
5
4
|
*/
|
|
6
|
-
export declare class RequestBodyInterceptor implements
|
|
5
|
+
export declare class RequestBodyInterceptor implements Interceptor {
|
|
7
6
|
/**
|
|
8
7
|
* 尝试转换请求体为合法的 fetch API body 类型
|
|
9
8
|
*
|
|
@@ -23,9 +22,9 @@ export declare class RequestBodyInterceptor implements RequestInterceptor {
|
|
|
23
22
|
*
|
|
24
23
|
* 对于不支持的 object 类型(如普通对象),将自动转换为 JSON 字符串
|
|
25
24
|
*
|
|
26
|
-
* @param
|
|
25
|
+
* @param exchange
|
|
27
26
|
* @returns 转换后的请求
|
|
28
27
|
*/
|
|
29
|
-
intercept(
|
|
28
|
+
intercept(exchange: FetchExchange): FetchExchange;
|
|
30
29
|
}
|
|
31
30
|
//# sourceMappingURL=requestBodyInterceptor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestBodyInterceptor.d.ts","sourceRoot":"","sources":["../src/requestBodyInterceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"requestBodyInterceptor.d.ts","sourceRoot":"","sources":["../src/requestBodyInterceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG3D;;GAEG;AACH,qBAAa,sBAAuB,YAAW,WAAW;IACxD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,aAAa;CA2ClD"}
|
package/dist/timeout.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FetchExchange } from './interceptor';
|
|
2
2
|
/**
|
|
3
3
|
* 定义具有超时能力的接口
|
|
4
4
|
*/
|
|
@@ -22,8 +22,7 @@ export declare function resolveTimeout(requestTimeout?: number, optionsTimeout?:
|
|
|
22
22
|
* 当HTTP请求超时时抛出此异常
|
|
23
23
|
*/
|
|
24
24
|
export declare class FetchTimeoutError extends Error {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
constructor(url: string, request: FetcherRequest, timeout: number);
|
|
25
|
+
exchange: FetchExchange;
|
|
26
|
+
constructor(exchange: FetchExchange, timeout: number);
|
|
28
27
|
}
|
|
29
28
|
//# sourceMappingURL=timeout.d.ts.map
|
package/dist/timeout.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,GAAG,SAAS,CAKpB;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,EAAE,aAAa,CAAC;gBAEZ,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM;CAUrD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ahoo-wang/fetcher",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Core library providing basic HTTP client functionality for Fetcher",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fetch",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
27
28
|
"import": "./dist/index.es.js",
|
|
28
|
-
"require": "./dist/index.umd.js"
|
|
29
|
-
"types": "./dist/index.d.ts"
|
|
29
|
+
"require": "./dist/index.umd.js"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"files": [
|