@ahoo-wang/fetcher 0.9.1 → 0.9.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 +3 -2
- package/README.zh-CN.md +2 -2
- package/dist/fetcher.d.ts +82 -12
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/fetcherError.d.ts +122 -0
- package/dist/fetcherError.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +230 -122
- package/dist/index.umd.js +1 -1
- package/dist/timeout.d.ts +0 -28
- package/dist/timeout.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
9
9
|
[](https://deepwiki.com/Ahoo-Wang/fetcher)
|
|
10
10
|
|
|
11
|
-
A modern, ultra-lightweight (
|
|
11
|
+
A modern, ultra-lightweight (2.3KiB) HTTP client with built-in path parameters, query parameters, and Axios-like API.
|
|
12
|
+
83%
|
|
12
13
|
smaller than Axios while providing the same powerful features.
|
|
13
14
|
|
|
14
15
|
## 🌟 Features
|
|
15
16
|
|
|
16
|
-
- **⚡ Ultra-Lightweight**: Only
|
|
17
|
+
- **⚡ Ultra-Lightweight**: Only 2.3KiB min+gzip - 83% smaller than Axios
|
|
17
18
|
- **🧭 Path & Query Parameters**: Built-in support for path (`{id}`) and query parameters
|
|
18
19
|
- **🔗 Interceptor System**: Request, response, and error interceptors for middleware patterns
|
|
19
20
|
- **⏱️ Timeout Control**: Configurable request timeouts with proper error handling
|
package/README.zh-CN.md
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[](https://www.npmjs.com/package/@ahoo-wang/fetcher)
|
|
9
9
|
[](https://deepwiki.com/Ahoo-Wang/fetcher)
|
|
10
10
|
|
|
11
|
-
一个现代、超轻量级(
|
|
11
|
+
一个现代、超轻量级(2.3kB)的 HTTP 客户端,内置路径参数、查询参数和类似 Axios 的 API。比 Axios 小 83%,同时提供相同的强大功能。
|
|
12
12
|
|
|
13
13
|
## 🌟 特性
|
|
14
14
|
|
|
15
|
-
- **⚡ 超轻量级**:仅
|
|
15
|
+
- **⚡ 超轻量级**:仅 2.3KiB min+gzip - 比 Axios 小 83%
|
|
16
16
|
- **🧭 路径和查询参数**:内置支持路径(`{id}`)和查询参数
|
|
17
17
|
- **🔗 拦截器系统**:请求、响应和错误拦截器的中间件模式
|
|
18
18
|
- **⏱️ 超时控制**:可配置的请求超时和适当的错误处理
|
package/dist/fetcher.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export declare class Fetcher implements UrlBuilderCapable, RequestHeadersCapable
|
|
|
65
65
|
* @param url - The URL path for the request (relative to baseURL if set)
|
|
66
66
|
* @param request - Request configuration including headers, body, parameters, etc.
|
|
67
67
|
* @returns Promise that resolves to the HTTP response
|
|
68
|
-
* @throws
|
|
68
|
+
* @throws FetchError if the request fails and no response is generated
|
|
69
69
|
*/
|
|
70
70
|
fetch(url: string, request?: FetchRequestInit): Promise<Response>;
|
|
71
71
|
/**
|
|
@@ -81,20 +81,90 @@ export declare class Fetcher implements UrlBuilderCapable, RequestHeadersCapable
|
|
|
81
81
|
*/
|
|
82
82
|
request(request: FetchRequest): Promise<FetchExchange>;
|
|
83
83
|
/**
|
|
84
|
-
* Processes a FetchExchange through the interceptor
|
|
84
|
+
* Processes a FetchExchange through the interceptor pipeline.
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* This method is the core of the Fetcher's interceptor system. It executes the three
|
|
87
|
+
* phases of interceptors in sequence:
|
|
88
|
+
* 1. Request interceptors - Process the request before sending
|
|
89
|
+
* 2. Response interceptors - Process the response after receiving
|
|
90
|
+
* 3. Error interceptors - Handle any errors that occurred during the process
|
|
89
91
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* - Otherwise, the original error is re-thrown
|
|
92
|
+
* The interceptor pipeline follows the Chain of Responsibility pattern, where each
|
|
93
|
+
* interceptor can modify the exchange object and decide whether to continue or
|
|
94
|
+
* terminate the chain.
|
|
94
95
|
*
|
|
95
|
-
* @param fetchExchange - The exchange object containing request and
|
|
96
|
-
* @returns Promise
|
|
97
|
-
* @throws
|
|
96
|
+
* @param fetchExchange - The exchange object containing request, response, and error information
|
|
97
|
+
* @returns Promise that resolves to the processed FetchExchange
|
|
98
|
+
* @throws ExchangeError if an unhandled error occurs during processing
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* The method handles three distinct phases:
|
|
102
|
+
*
|
|
103
|
+
* 1. Request Phase: Executes request interceptors which can modify headers, URL, body, etc.
|
|
104
|
+
* Built-in interceptors handle URL resolution, body serialization, and actual HTTP execution.
|
|
105
|
+
*
|
|
106
|
+
* 2. Response Phase: Executes response interceptors which can transform or validate responses.
|
|
107
|
+
* These interceptors only run if the request phase completed without throwing.
|
|
108
|
+
*
|
|
109
|
+
* 3. Error Phase: Executes error interceptors when any phase throws an error. Error interceptors
|
|
110
|
+
* can handle errors by clearing the error property. If error interceptors clear the error,
|
|
111
|
+
* the exchange is returned successfully.
|
|
112
|
+
*
|
|
113
|
+
* Error Handling:
|
|
114
|
+
* - If any interceptor throws an error, the error phase is triggered
|
|
115
|
+
* - Error interceptors can "fix" errors by clearing the error property on the exchange
|
|
116
|
+
* - If errors remain after error interceptors run, they are wrapped in ExchangeError
|
|
117
|
+
*
|
|
118
|
+
* Order of Execution:
|
|
119
|
+
* 1. Request interceptors (sorted by order property, ascending)
|
|
120
|
+
* 2. Response interceptors (sorted by order property, ascending) - only if no error in request phase
|
|
121
|
+
* 3. Error interceptors (sorted by order property, ascending) - only if an error occurred
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* // Create a fetcher with custom interceptors
|
|
126
|
+
* const fetcher = new Fetcher();
|
|
127
|
+
*
|
|
128
|
+
* // Add a request interceptor
|
|
129
|
+
* fetcher.interceptors.request.use({
|
|
130
|
+
* name: 'AuthInterceptor',
|
|
131
|
+
* order: 100,
|
|
132
|
+
* async intercept(exchange: FetchExchange) {
|
|
133
|
+
* exchange.request.headers = {
|
|
134
|
+
* ...exchange.request.headers,
|
|
135
|
+
* 'Authorization': 'Bearer ' + getToken()
|
|
136
|
+
* };
|
|
137
|
+
* }
|
|
138
|
+
* });
|
|
139
|
+
*
|
|
140
|
+
* // Add a response interceptor
|
|
141
|
+
* fetcher.interceptors.response.use({
|
|
142
|
+
* name: 'ResponseLogger',
|
|
143
|
+
* order: 100,
|
|
144
|
+
* async intercept(exchange: FetchExchange) {
|
|
145
|
+
* console.log(`Response status: ${exchange.response?.status}`);
|
|
146
|
+
* }
|
|
147
|
+
* });
|
|
148
|
+
*
|
|
149
|
+
* // Add an error interceptor
|
|
150
|
+
* fetcher.interceptors.error.use({
|
|
151
|
+
* name: 'ErrorLogger',
|
|
152
|
+
* order: 100,
|
|
153
|
+
* async intercept(exchange: FetchExchange) {
|
|
154
|
+
* console.error(`Request to ${exchange.request.url} failed:`, exchange.error);
|
|
155
|
+
* // Clear the error to indicate it's been handled
|
|
156
|
+
* exchange.error = undefined;
|
|
157
|
+
* }
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* // Create and process an exchange
|
|
161
|
+
* const request: FetchRequest = {
|
|
162
|
+
* url: '/api/users',
|
|
163
|
+
* method: HttpMethod.GET
|
|
164
|
+
* };
|
|
165
|
+
* const exchange = new FetchExchange(fetcher, request);
|
|
166
|
+
* const result = await fetcher.exchange(exchange);
|
|
167
|
+
* ```
|
|
98
168
|
*/
|
|
99
169
|
exchange(fetchExchange: FetchExchange): Promise<FetchExchange>;
|
|
100
170
|
/**
|
package/dist/fetcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAkB,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAEhB,cAAc,EACd,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAkB,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,cAAc,EAEd,YAAY,EACZ,gBAAgB,EAEhB,cAAc,EACd,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,cACf,SAAQ,cAAc,EACpB,qBAAqB,EACrB,cAAc;IAChB,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAMD,eAAO,MAAM,eAAe,EAAE,cAG7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,OACX,YAAW,iBAAiB,EAAE,qBAAqB,EAAE,cAAc;IACnE,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAmB;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,mBAAmB,CAAC;IAElC;;;;;;;OAOG;gBACS,OAAO,GAAE,cAAgC;IAOrD;;;;;;;;;;OAUG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAU3E;;;;;;;;;;OAUG;IACG,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAa5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqFG;IACG,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAsBpE;;;;;;;;;;OAUG;YACW,WAAW;IAWzB;;;;;;;;;OASG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;OAQG;IACG,IAAI,CACR,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;OAQG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;OAQG;IACG,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;OAQG;IACG,KAAK,CACT,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;;OASG;IACG,IAAI,CACR,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;IAIpB;;;;;;;;;OASG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,MAAM,CAAM,GACtD,OAAO,CAAC,QAAQ,CAAC;CAGrB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { FetchExchange } from './fetchExchange';
|
|
2
|
+
import { FetchRequest } from './fetchRequest';
|
|
3
|
+
/**
|
|
4
|
+
* Base error class for all Fetcher-related errors.
|
|
5
|
+
*
|
|
6
|
+
* This class extends the native Error class and provides a foundation for
|
|
7
|
+
* all custom errors thrown by the Fetcher library. It includes support for
|
|
8
|
+
* error chaining through the cause property.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* try {
|
|
13
|
+
* await fetcher.get('/api/users');
|
|
14
|
+
* } catch (error) {
|
|
15
|
+
* if (error instanceof FetcherError) {
|
|
16
|
+
* console.log('Fetcher error:', error.message);
|
|
17
|
+
* if (error.cause) {
|
|
18
|
+
* console.log('Caused by:', error.cause);
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class FetcherError extends Error {
|
|
25
|
+
readonly cause?: (Error | any) | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new FetcherError instance.
|
|
28
|
+
*
|
|
29
|
+
* @param errorMsg - Optional error message. If not provided, will use the cause's message or a default message.
|
|
30
|
+
* @param cause - Optional underlying error that caused this error.
|
|
31
|
+
*/
|
|
32
|
+
constructor(errorMsg?: string, cause?: (Error | any) | undefined);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Custom error class for FetchExchange related errors.
|
|
36
|
+
*
|
|
37
|
+
* This error is thrown when there are issues with the HTTP exchange process,
|
|
38
|
+
* such as when a request fails and no response is generated. It provides
|
|
39
|
+
* comprehensive information about the failed request through the exchange object.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* try {
|
|
44
|
+
* await fetcher.get('/api/users');
|
|
45
|
+
* } catch (error) {
|
|
46
|
+
* if (error instanceof ExchangeError) {
|
|
47
|
+
* console.log('Request URL:', error.exchange.request.url);
|
|
48
|
+
* console.log('Request method:', error.exchange.request.method);
|
|
49
|
+
* if (error.exchange.error) {
|
|
50
|
+
* console.log('Underlying error:', error.exchange.error);
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare class ExchangeError extends FetcherError {
|
|
57
|
+
readonly exchange: FetchExchange;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new ExchangeError instance.
|
|
60
|
+
*
|
|
61
|
+
* @param exchange - The FetchExchange object containing request/response/error information.
|
|
62
|
+
*/
|
|
63
|
+
constructor(exchange: FetchExchange);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Custom error class for Fetcher request failures.
|
|
67
|
+
*
|
|
68
|
+
* This error is thrown when a fetch request fails and no response is generated.
|
|
69
|
+
* It wraps the FetchExchange object to provide comprehensive information about the failed request.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* try {
|
|
74
|
+
* await fetcher.get('/api/users');
|
|
75
|
+
* } catch (error) {
|
|
76
|
+
* if (error instanceof FetchError) {
|
|
77
|
+
* console.log('Failed URL:', error.exchange.request.url);
|
|
78
|
+
* console.log('Request headers:', error.exchange.request.headers);
|
|
79
|
+
* console.log('Interceptor attributes:', error.exchange.attributes);
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare class FetchError extends FetcherError {
|
|
85
|
+
readonly exchange: FetchExchange;
|
|
86
|
+
/**
|
|
87
|
+
* Creates a new FetchError instance.
|
|
88
|
+
*
|
|
89
|
+
* @param exchange - The FetchExchange object containing request/response/error information.
|
|
90
|
+
* @param errorMsg - Optional custom error message. If not provided, will use the exchange's error message.
|
|
91
|
+
*/
|
|
92
|
+
constructor(exchange: FetchExchange, errorMsg?: string);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Exception class thrown when an HTTP request times out.
|
|
96
|
+
*
|
|
97
|
+
* This error is thrown by the timeoutFetch function when a request exceeds its timeout limit.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* try {
|
|
102
|
+
* const response = await timeoutFetch('https://api.example.com/users', {}, 1000);
|
|
103
|
+
* } catch (error) {
|
|
104
|
+
* if (error instanceof FetchTimeoutError) {
|
|
105
|
+
* console.log(`Request timed out after ${error.timeout}ms`);
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare class FetchTimeoutError extends FetcherError {
|
|
111
|
+
/**
|
|
112
|
+
* The request options that timed out.
|
|
113
|
+
*/
|
|
114
|
+
request: FetchRequest;
|
|
115
|
+
/**
|
|
116
|
+
* Creates a new FetchTimeoutError instance.
|
|
117
|
+
*
|
|
118
|
+
* @param request - The request options that timed out
|
|
119
|
+
*/
|
|
120
|
+
constructor(request: FetchRequest);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=fetcherError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcherError.d.ts","sourceRoot":"","sources":["../src/fetcherError.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAa,SAAQ,KAAK;aASnB,KAAK,CAAC,GAAE,KAAK,GAAG,GAAG;IARrC;;;;;OAKG;gBAED,QAAQ,CAAC,EAAE,MAAM,EACD,KAAK,CAAC,GAAE,KAAK,GAAG,GAAG,aAAA;CAetC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAc,SAAQ,YAAY;aAMjB,QAAQ,EAAE,aAAa;IALnD;;;;OAIG;gBACyB,QAAQ,EAAE,aAAa;CASpD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,UAAW,SAAQ,YAAY;aAQxB,QAAQ,EAAE,aAAa;IAPzC;;;;;OAKG;gBAEe,QAAQ,EAAE,aAAa,EACvC,QAAQ,CAAC,EAAE,MAAM;CAUpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IACjD;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;;;OAIG;gBACS,OAAO,EAAE,YAAY;CASlC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC"}
|
package/dist/index.es.js
CHANGED
|
@@ -1,10 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
class a extends Error {
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new FetcherError instance.
|
|
4
|
+
*
|
|
5
|
+
* @param errorMsg - Optional error message. If not provided, will use the cause's message or a default message.
|
|
6
|
+
* @param cause - Optional underlying error that caused this error.
|
|
7
|
+
*/
|
|
8
|
+
constructor(e, t) {
|
|
9
|
+
const s = e || t?.message || "An error occurred in the fetcher";
|
|
10
|
+
super(s), this.cause = t, this.name = "FetcherError", t?.stack && (this.stack = t.stack), Object.setPrototypeOf(this, a.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class f extends a {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new ExchangeError instance.
|
|
16
|
+
*
|
|
17
|
+
* @param exchange - The FetchExchange object containing request/response/error information.
|
|
18
|
+
*/
|
|
19
|
+
constructor(e) {
|
|
20
|
+
const t = e.error?.message || e.response?.statusText || `Request to ${e.request.url} failed during exchange`;
|
|
21
|
+
super(t, e.error), this.exchange = e, this.name = "ExchangeError", Object.setPrototypeOf(this, f.prototype);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class y extends a {
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new FetchError instance.
|
|
27
|
+
*
|
|
28
|
+
* @param exchange - The FetchExchange object containing request/response/error information.
|
|
29
|
+
* @param errorMsg - Optional custom error message. If not provided, will use the exchange's error message.
|
|
30
|
+
*/
|
|
31
|
+
constructor(e, t) {
|
|
32
|
+
const s = t || e.error?.message || `Request to ${e.request.url} failed with no response`;
|
|
33
|
+
super(s, e.error), this.exchange = e, this.name = "FetchError", Object.setPrototypeOf(this, y.prototype);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class E extends a {
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new FetchTimeoutError instance.
|
|
39
|
+
*
|
|
40
|
+
* @param request - The request options that timed out
|
|
41
|
+
*/
|
|
42
|
+
constructor(e) {
|
|
43
|
+
const t = e.method || "GET", s = `Request timeout of ${e.timeout}ms exceeded for ${t} ${e.url}`;
|
|
44
|
+
super(s), this.name = "FetchTimeoutError", this.request = e, Object.setPrototypeOf(this, E.prototype);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function w(r) {
|
|
2
48
|
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(r);
|
|
3
49
|
}
|
|
4
|
-
function
|
|
5
|
-
return
|
|
50
|
+
function P(r, e) {
|
|
51
|
+
return w(e) ? e : e ? r.replace(/\/?\/$/, "") + "/" + e.replace(/^\/+/, "") : r;
|
|
6
52
|
}
|
|
7
|
-
class
|
|
53
|
+
class R {
|
|
8
54
|
/**
|
|
9
55
|
* Initializes a new UrlBuilder instance.
|
|
10
56
|
*
|
|
@@ -37,13 +83,13 @@ class g {
|
|
|
37
83
|
* ```
|
|
38
84
|
*/
|
|
39
85
|
build(e, t) {
|
|
40
|
-
const s = t?.path,
|
|
41
|
-
let
|
|
42
|
-
if (
|
|
43
|
-
const u = new URLSearchParams(
|
|
44
|
-
u && (
|
|
86
|
+
const s = t?.path, o = t?.query, i = P(this.baseURL, e);
|
|
87
|
+
let n = this.interpolateUrl(i, s);
|
|
88
|
+
if (o) {
|
|
89
|
+
const u = new URLSearchParams(o).toString();
|
|
90
|
+
u && (n += "?" + u);
|
|
45
91
|
}
|
|
46
|
-
return
|
|
92
|
+
return n;
|
|
47
93
|
}
|
|
48
94
|
/**
|
|
49
95
|
* Resolves a complete URL from a FetchRequest.
|
|
@@ -85,57 +131,46 @@ class g {
|
|
|
85
131
|
* ```
|
|
86
132
|
*/
|
|
87
133
|
interpolateUrl(e, t) {
|
|
88
|
-
return t ? e.replace(/{([^}]+)}/g, (s,
|
|
89
|
-
const i = t[
|
|
134
|
+
return t ? e.replace(/{([^}]+)}/g, (s, o) => {
|
|
135
|
+
const i = t[o];
|
|
90
136
|
if (i === void 0)
|
|
91
|
-
throw new Error(`Missing required path parameter: ${
|
|
137
|
+
throw new Error(`Missing required path parameter: ${o}`);
|
|
92
138
|
return String(i);
|
|
93
139
|
}) : e;
|
|
94
140
|
}
|
|
95
141
|
}
|
|
96
|
-
function
|
|
142
|
+
function F(r, e) {
|
|
97
143
|
return typeof r < "u" ? r : e;
|
|
98
144
|
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Creates a new FetchTimeoutError instance.
|
|
102
|
-
*
|
|
103
|
-
* @param request - The request options that timed out
|
|
104
|
-
*/
|
|
105
|
-
constructor(e) {
|
|
106
|
-
const t = e.method || "GET", s = `Request timeout of ${e.timeout}ms exceeded for ${t} ${e.url}`;
|
|
107
|
-
super(s), this.name = "FetchTimeoutError", this.request = e, Object.setPrototypeOf(this, p.prototype);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
async function P(r) {
|
|
145
|
+
async function A(r) {
|
|
111
146
|
const e = r.url, t = r.timeout, s = r;
|
|
112
147
|
if (!t)
|
|
113
148
|
return fetch(e, s);
|
|
114
|
-
const
|
|
149
|
+
const o = new AbortController(), i = {
|
|
115
150
|
...s,
|
|
116
|
-
signal:
|
|
151
|
+
signal: o.signal
|
|
117
152
|
};
|
|
118
|
-
let
|
|
119
|
-
const u = new Promise((
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
153
|
+
let n = null;
|
|
154
|
+
const u = new Promise((D, I) => {
|
|
155
|
+
n = setTimeout(() => {
|
|
156
|
+
n && clearTimeout(n);
|
|
157
|
+
const b = new E(r);
|
|
158
|
+
o.abort(b), I(b);
|
|
124
159
|
}, t);
|
|
125
160
|
});
|
|
126
161
|
try {
|
|
127
162
|
return await Promise.race([fetch(e, i), u]);
|
|
128
163
|
} finally {
|
|
129
|
-
|
|
164
|
+
n && clearTimeout(n);
|
|
130
165
|
}
|
|
131
166
|
}
|
|
132
|
-
function
|
|
167
|
+
function h(r, e) {
|
|
133
168
|
return e ? r.filter(e).sort((t, s) => t.order - s.order) : [...r].sort((t, s) => t.order - s.order);
|
|
134
169
|
}
|
|
135
170
|
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 || {});
|
|
136
|
-
const
|
|
137
|
-
var
|
|
138
|
-
class
|
|
171
|
+
const G = "Content-Type";
|
|
172
|
+
var T = /* @__PURE__ */ ((r) => (r.APPLICATION_JSON = "application/json", r.TEXT_EVENT_STREAM = "text/event-stream", r))(T || {});
|
|
173
|
+
class O {
|
|
139
174
|
constructor() {
|
|
140
175
|
this.name = "RequestBodyInterceptor", this.order = Number.MIN_SAFE_INTEGER + 200;
|
|
141
176
|
}
|
|
@@ -183,11 +218,11 @@ class R {
|
|
|
183
218
|
return;
|
|
184
219
|
const s = { ...t };
|
|
185
220
|
s.body = JSON.stringify(t.body), s.headers || (s.headers = {});
|
|
186
|
-
const
|
|
187
|
-
|
|
221
|
+
const o = s.headers;
|
|
222
|
+
o["Content-Type"] || (o["Content-Type"] = T.APPLICATION_JSON), e.request = s;
|
|
188
223
|
}
|
|
189
224
|
}
|
|
190
|
-
class
|
|
225
|
+
class q {
|
|
191
226
|
constructor() {
|
|
192
227
|
this.name = "FetchInterceptor", this.order = Number.MAX_SAFE_INTEGER - 100;
|
|
193
228
|
}
|
|
@@ -217,10 +252,10 @@ class F {
|
|
|
217
252
|
* console.log(exchange.response); // HTTP response object
|
|
218
253
|
*/
|
|
219
254
|
async intercept(e) {
|
|
220
|
-
e.response = await
|
|
255
|
+
e.response = await A(e.request);
|
|
221
256
|
}
|
|
222
257
|
}
|
|
223
|
-
class
|
|
258
|
+
class N {
|
|
224
259
|
constructor() {
|
|
225
260
|
this.name = "UrlResolveInterceptor", this.order = Number.MIN_SAFE_INTEGER + 100;
|
|
226
261
|
}
|
|
@@ -234,7 +269,7 @@ class A {
|
|
|
234
269
|
t.url = e.fetcher.urlBuilder.resolveRequestUrl(t);
|
|
235
270
|
}
|
|
236
271
|
}
|
|
237
|
-
class
|
|
272
|
+
class d {
|
|
238
273
|
/**
|
|
239
274
|
* Initializes a new InterceptorManager instance.
|
|
240
275
|
*
|
|
@@ -245,7 +280,7 @@ class h {
|
|
|
245
280
|
* upon construction.
|
|
246
281
|
*/
|
|
247
282
|
constructor(e = []) {
|
|
248
|
-
this.sortedInterceptors = [], this.sortedInterceptors =
|
|
283
|
+
this.sortedInterceptors = [], this.sortedInterceptors = h(e);
|
|
249
284
|
}
|
|
250
285
|
/**
|
|
251
286
|
* Gets the name of this interceptor manager.
|
|
@@ -277,7 +312,7 @@ class h {
|
|
|
277
312
|
* After adding, interceptors are automatically sorted by their order property.
|
|
278
313
|
*/
|
|
279
314
|
use(e) {
|
|
280
|
-
return this.sortedInterceptors.some((t) => t.name === e.name) ? !1 : (this.sortedInterceptors =
|
|
315
|
+
return this.sortedInterceptors.some((t) => t.name === e.name) ? !1 : (this.sortedInterceptors = h([
|
|
281
316
|
...this.sortedInterceptors,
|
|
282
317
|
e
|
|
283
318
|
]), !0);
|
|
@@ -291,7 +326,7 @@ class h {
|
|
|
291
326
|
*/
|
|
292
327
|
eject(e) {
|
|
293
328
|
const t = this.sortedInterceptors;
|
|
294
|
-
return this.sortedInterceptors =
|
|
329
|
+
return this.sortedInterceptors = h(
|
|
295
330
|
t,
|
|
296
331
|
(s) => s.name !== e
|
|
297
332
|
), t.length !== this.sortedInterceptors.length;
|
|
@@ -321,18 +356,18 @@ class h {
|
|
|
321
356
|
await t.intercept(e);
|
|
322
357
|
}
|
|
323
358
|
}
|
|
324
|
-
class
|
|
359
|
+
class S {
|
|
325
360
|
constructor() {
|
|
326
|
-
this.request = new
|
|
327
|
-
new
|
|
328
|
-
new
|
|
329
|
-
new
|
|
330
|
-
]), this.response = new
|
|
361
|
+
this.request = new d([
|
|
362
|
+
new N(),
|
|
363
|
+
new O(),
|
|
364
|
+
new q()
|
|
365
|
+
]), this.response = new d(), this.error = new d();
|
|
331
366
|
}
|
|
332
367
|
}
|
|
333
|
-
class
|
|
334
|
-
constructor(e, t, s,
|
|
335
|
-
this.attributes = {}, this.fetcher = e, this.request = t, this.response = s, this.error =
|
|
368
|
+
class U {
|
|
369
|
+
constructor(e, t, s, o) {
|
|
370
|
+
this.attributes = {}, this.fetcher = e, this.request = t, this.response = s, this.error = o;
|
|
336
371
|
}
|
|
337
372
|
/**
|
|
338
373
|
* Checks if the exchange has an error.
|
|
@@ -351,17 +386,17 @@ class S {
|
|
|
351
386
|
return !!this.response;
|
|
352
387
|
}
|
|
353
388
|
}
|
|
354
|
-
function
|
|
389
|
+
function l(r, e) {
|
|
355
390
|
if (!(r === void 0 && e === void 0))
|
|
356
391
|
return e === void 0 ? r : r === void 0 ? e : { ...r, ...e };
|
|
357
392
|
}
|
|
358
|
-
const
|
|
359
|
-
"Content-Type":
|
|
360
|
-
},
|
|
393
|
+
const p = {
|
|
394
|
+
"Content-Type": T.APPLICATION_JSON
|
|
395
|
+
}, g = {
|
|
361
396
|
baseURL: "",
|
|
362
|
-
headers:
|
|
397
|
+
headers: p
|
|
363
398
|
};
|
|
364
|
-
class
|
|
399
|
+
class _ {
|
|
365
400
|
/**
|
|
366
401
|
* Initializes a new Fetcher instance with optional configuration.
|
|
367
402
|
*
|
|
@@ -370,8 +405,8 @@ class q {
|
|
|
370
405
|
*
|
|
371
406
|
* @param options - Configuration options for the Fetcher instance
|
|
372
407
|
*/
|
|
373
|
-
constructor(e =
|
|
374
|
-
this.headers =
|
|
408
|
+
constructor(e = g) {
|
|
409
|
+
this.headers = p, this.urlBuilder = new R(e.baseURL), this.headers = e.headers ?? p, this.timeout = e.timeout, this.interceptors = e.interceptors ?? new S();
|
|
375
410
|
}
|
|
376
411
|
/**
|
|
377
412
|
* Executes an HTTP request with the specified URL and options.
|
|
@@ -382,15 +417,15 @@ class q {
|
|
|
382
417
|
* @param url - The URL path for the request (relative to baseURL if set)
|
|
383
418
|
* @param request - Request configuration including headers, body, parameters, etc.
|
|
384
419
|
* @returns Promise that resolves to the HTTP response
|
|
385
|
-
* @throws
|
|
420
|
+
* @throws FetchError if the request fails and no response is generated
|
|
386
421
|
*/
|
|
387
422
|
async fetch(e, t = {}) {
|
|
388
423
|
const s = t;
|
|
389
424
|
s.url = e;
|
|
390
|
-
const
|
|
391
|
-
if (!
|
|
392
|
-
throw new
|
|
393
|
-
return
|
|
425
|
+
const o = await this.request(s);
|
|
426
|
+
if (!o.response)
|
|
427
|
+
throw new y(o, `Request to ${s.url} failed with no response`);
|
|
428
|
+
return o.response;
|
|
394
429
|
}
|
|
395
430
|
/**
|
|
396
431
|
* Processes an HTTP request through the Fetcher's internal workflow.
|
|
@@ -404,36 +439,106 @@ class q {
|
|
|
404
439
|
* @throws Error if an unhandled error occurs during request processing
|
|
405
440
|
*/
|
|
406
441
|
async request(e) {
|
|
407
|
-
const t =
|
|
442
|
+
const t = l(e.headers, this.headers), s = {
|
|
408
443
|
...e,
|
|
409
444
|
headers: t,
|
|
410
|
-
timeout:
|
|
411
|
-
},
|
|
412
|
-
return this.exchange(
|
|
445
|
+
timeout: F(e.timeout, this.timeout)
|
|
446
|
+
}, o = new U(this, s);
|
|
447
|
+
return this.exchange(o);
|
|
413
448
|
}
|
|
414
449
|
/**
|
|
415
|
-
* Processes a FetchExchange through the interceptor
|
|
450
|
+
* Processes a FetchExchange through the interceptor pipeline.
|
|
451
|
+
*
|
|
452
|
+
* This method is the core of the Fetcher's interceptor system. It executes the three
|
|
453
|
+
* phases of interceptors in sequence:
|
|
454
|
+
* 1. Request interceptors - Process the request before sending
|
|
455
|
+
* 2. Response interceptors - Process the response after receiving
|
|
456
|
+
* 3. Error interceptors - Handle any errors that occurred during the process
|
|
457
|
+
*
|
|
458
|
+
* The interceptor pipeline follows the Chain of Responsibility pattern, where each
|
|
459
|
+
* interceptor can modify the exchange object and decide whether to continue or
|
|
460
|
+
* terminate the chain.
|
|
461
|
+
*
|
|
462
|
+
* @param fetchExchange - The exchange object containing request, response, and error information
|
|
463
|
+
* @returns Promise that resolves to the processed FetchExchange
|
|
464
|
+
* @throws ExchangeError if an unhandled error occurs during processing
|
|
465
|
+
*
|
|
466
|
+
* @remarks
|
|
467
|
+
* The method handles three distinct phases:
|
|
468
|
+
*
|
|
469
|
+
* 1. Request Phase: Executes request interceptors which can modify headers, URL, body, etc.
|
|
470
|
+
* Built-in interceptors handle URL resolution, body serialization, and actual HTTP execution.
|
|
471
|
+
*
|
|
472
|
+
* 2. Response Phase: Executes response interceptors which can transform or validate responses.
|
|
473
|
+
* These interceptors only run if the request phase completed without throwing.
|
|
416
474
|
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
475
|
+
* 3. Error Phase: Executes error interceptors when any phase throws an error. Error interceptors
|
|
476
|
+
* can handle errors by clearing the error property. If error interceptors clear the error,
|
|
477
|
+
* the exchange is returned successfully.
|
|
420
478
|
*
|
|
421
|
-
* Error
|
|
422
|
-
* - If an error
|
|
423
|
-
* -
|
|
424
|
-
* -
|
|
479
|
+
* Error Handling:
|
|
480
|
+
* - If any interceptor throws an error, the error phase is triggered
|
|
481
|
+
* - Error interceptors can "fix" errors by clearing the error property on the exchange
|
|
482
|
+
* - If errors remain after error interceptors run, they are wrapped in ExchangeError
|
|
425
483
|
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
484
|
+
* Order of Execution:
|
|
485
|
+
* 1. Request interceptors (sorted by order property, ascending)
|
|
486
|
+
* 2. Response interceptors (sorted by order property, ascending) - only if no error in request phase
|
|
487
|
+
* 3. Error interceptors (sorted by order property, ascending) - only if an error occurred
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* // Create a fetcher with custom interceptors
|
|
492
|
+
* const fetcher = new Fetcher();
|
|
493
|
+
*
|
|
494
|
+
* // Add a request interceptor
|
|
495
|
+
* fetcher.interceptors.request.use({
|
|
496
|
+
* name: 'AuthInterceptor',
|
|
497
|
+
* order: 100,
|
|
498
|
+
* async intercept(exchange: FetchExchange) {
|
|
499
|
+
* exchange.request.headers = {
|
|
500
|
+
* ...exchange.request.headers,
|
|
501
|
+
* 'Authorization': 'Bearer ' + getToken()
|
|
502
|
+
* };
|
|
503
|
+
* }
|
|
504
|
+
* });
|
|
505
|
+
*
|
|
506
|
+
* // Add a response interceptor
|
|
507
|
+
* fetcher.interceptors.response.use({
|
|
508
|
+
* name: 'ResponseLogger',
|
|
509
|
+
* order: 100,
|
|
510
|
+
* async intercept(exchange: FetchExchange) {
|
|
511
|
+
* console.log(`Response status: ${exchange.response?.status}`);
|
|
512
|
+
* }
|
|
513
|
+
* });
|
|
514
|
+
*
|
|
515
|
+
* // Add an error interceptor
|
|
516
|
+
* fetcher.interceptors.error.use({
|
|
517
|
+
* name: 'ErrorLogger',
|
|
518
|
+
* order: 100,
|
|
519
|
+
* async intercept(exchange: FetchExchange) {
|
|
520
|
+
* console.error(`Request to ${exchange.request.url} failed:`, exchange.error);
|
|
521
|
+
* // Clear the error to indicate it's been handled
|
|
522
|
+
* exchange.error = undefined;
|
|
523
|
+
* }
|
|
524
|
+
* });
|
|
525
|
+
*
|
|
526
|
+
* // Create and process an exchange
|
|
527
|
+
* const request: FetchRequest = {
|
|
528
|
+
* url: '/api/users',
|
|
529
|
+
* method: HttpMethod.GET
|
|
530
|
+
* };
|
|
531
|
+
* const exchange = new FetchExchange(fetcher, request);
|
|
532
|
+
* const result = await fetcher.exchange(exchange);
|
|
533
|
+
* ```
|
|
429
534
|
*/
|
|
430
535
|
async exchange(e) {
|
|
431
536
|
try {
|
|
432
537
|
return await this.interceptors.request.intercept(e), await this.interceptors.response.intercept(e), e;
|
|
433
538
|
} catch (t) {
|
|
434
|
-
if (e.error = t, await this.interceptors.error.intercept(e), e.
|
|
539
|
+
if (e.error = t, await this.interceptors.error.intercept(e), !e.hasError())
|
|
435
540
|
return e;
|
|
436
|
-
throw e
|
|
541
|
+
throw new f(e);
|
|
437
542
|
}
|
|
438
543
|
}
|
|
439
544
|
/**
|
|
@@ -542,7 +647,7 @@ class q {
|
|
|
542
647
|
}
|
|
543
648
|
}
|
|
544
649
|
const m = "default";
|
|
545
|
-
class
|
|
650
|
+
class L {
|
|
546
651
|
constructor() {
|
|
547
652
|
this.registrar = /* @__PURE__ */ new Map();
|
|
548
653
|
}
|
|
@@ -642,31 +747,31 @@ class O {
|
|
|
642
747
|
return new Map(this.registrar);
|
|
643
748
|
}
|
|
644
749
|
}
|
|
645
|
-
const
|
|
646
|
-
function
|
|
750
|
+
const v = new L();
|
|
751
|
+
function j(r, e) {
|
|
647
752
|
if (Object.keys(r).length === 0)
|
|
648
753
|
return e;
|
|
649
754
|
if (Object.keys(e).length === 0)
|
|
650
755
|
return r;
|
|
651
756
|
const t = {
|
|
652
|
-
path:
|
|
653
|
-
query:
|
|
757
|
+
path: l(r.urlParams?.path, e.urlParams?.path),
|
|
758
|
+
query: l(r.urlParams?.query, e.urlParams?.query)
|
|
654
759
|
}, s = {
|
|
655
760
|
...r.headers,
|
|
656
761
|
...e.headers
|
|
657
|
-
},
|
|
762
|
+
}, o = e.method ?? r.method, i = e.body ?? r.body, n = e.timeout ?? r.timeout, u = e.signal ?? r.signal;
|
|
658
763
|
return {
|
|
659
764
|
...r,
|
|
660
765
|
...e,
|
|
661
|
-
method:
|
|
766
|
+
method: o,
|
|
662
767
|
urlParams: t,
|
|
663
768
|
headers: s,
|
|
664
769
|
body: i,
|
|
665
|
-
timeout:
|
|
770
|
+
timeout: n,
|
|
666
771
|
signal: u
|
|
667
772
|
};
|
|
668
773
|
}
|
|
669
|
-
class
|
|
774
|
+
class C extends _ {
|
|
670
775
|
/**
|
|
671
776
|
* Create a NamedFetcher instance and automatically register it with the global fetcherRegistrar
|
|
672
777
|
*
|
|
@@ -684,35 +789,38 @@ class _ extends q {
|
|
|
684
789
|
* headers: { 'Authorization': 'Bearer token' }
|
|
685
790
|
* });
|
|
686
791
|
*/
|
|
687
|
-
constructor(e, t =
|
|
688
|
-
super(t), this.name = e,
|
|
792
|
+
constructor(e, t = g) {
|
|
793
|
+
super(t), this.name = e, v.register(e, this);
|
|
689
794
|
}
|
|
690
795
|
}
|
|
691
|
-
const
|
|
796
|
+
const $ = new C(m);
|
|
692
797
|
export {
|
|
693
|
-
|
|
694
|
-
|
|
798
|
+
G as ContentTypeHeader,
|
|
799
|
+
T as ContentTypeValues,
|
|
695
800
|
m as DEFAULT_FETCHER_NAME,
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
q as
|
|
701
|
-
|
|
702
|
-
|
|
801
|
+
g as DEFAULT_OPTIONS,
|
|
802
|
+
f as ExchangeError,
|
|
803
|
+
y as FetchError,
|
|
804
|
+
U as FetchExchange,
|
|
805
|
+
q as FetchInterceptor,
|
|
806
|
+
E as FetchTimeoutError,
|
|
807
|
+
_ as Fetcher,
|
|
808
|
+
a as FetcherError,
|
|
809
|
+
S as FetcherInterceptors,
|
|
810
|
+
L as FetcherRegistrar,
|
|
703
811
|
c as HttpMethod,
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
812
|
+
d as InterceptorManager,
|
|
813
|
+
C as NamedFetcher,
|
|
814
|
+
O as RequestBodyInterceptor,
|
|
815
|
+
R as UrlBuilder,
|
|
816
|
+
N as UrlResolveInterceptor,
|
|
817
|
+
P as combineURLs,
|
|
818
|
+
$ as fetcher,
|
|
819
|
+
v as fetcherRegistrar,
|
|
820
|
+
w as isAbsoluteURL,
|
|
821
|
+
l as mergeRecords,
|
|
822
|
+
j as mergeRequest,
|
|
823
|
+
F as resolveTimeout,
|
|
824
|
+
A as timeoutFetch,
|
|
825
|
+
h as toSorted
|
|
718
826
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(n,
|
|
1
|
+
(function(n,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(n=typeof globalThis<"u"?globalThis:n||self,i(n.Fetcher={}))})(this,(function(n){"use strict";class i extends Error{constructor(e,t){const s=e||t?.message||"An error occurred in the fetcher";super(s),this.cause=t,this.name="FetcherError",t?.stack&&(this.stack=t.stack),Object.setPrototypeOf(this,i.prototype)}}class d extends i{constructor(e){const t=e.error?.message||e.response?.statusText||`Request to ${e.request.url} failed during exchange`;super(t,e.error),this.exchange=e,this.name="ExchangeError",Object.setPrototypeOf(this,d.prototype)}}class l extends i{constructor(e,t){const s=t||e.error?.message||`Request to ${e.request.url} failed with no response`;super(s,e.error),this.exchange=e,this.name="FetchError",Object.setPrototypeOf(this,l.prototype)}}class m extends i{constructor(e){const t=e.method||"GET",s=`Request timeout of ${e.timeout}ms exceeded for ${t} ${e.url}`;super(s),this.name="FetchTimeoutError",this.request=e,Object.setPrototypeOf(this,m.prototype)}}function F(r){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(r)}function I(r,e){return F(e)?e:e?r.replace(/\/?\/$/,"")+"/"+e.replace(/^\/+/,""):r}class R{constructor(e){this.baseURL=e}build(e,t){const s=t?.path,o=t?.query,a=I(this.baseURL,e);let c=this.interpolateUrl(a,s);if(o){const h=new URLSearchParams(o).toString();h&&(c+="?"+h)}return c}resolveRequestUrl(e){return this.build(e.url,e.urlParams)}interpolateUrl(e,t){return t?e.replace(/{([^}]+)}/g,(s,o)=>{const a=t[o];if(a===void 0)throw new Error(`Missing required path parameter: ${o}`);return String(a)}):e}}function P(r,e){return typeof r<"u"?r:e}async function w(r){const e=r.url,t=r.timeout,s=r;if(!t)return fetch(e,s);const o=new AbortController,a={...s,signal:o.signal};let c=null;const h=new Promise((G,B)=>{c=setTimeout(()=>{c&&clearTimeout(c);const C=new m(r);o.abort(C),B(C)},t)});try{return await Promise.race([fetch(e,a),h])}finally{c&&clearTimeout(c)}}function f(r,e){return e?r.filter(e).sort((t,s)=>t.order-s.order):[...r].sort((t,s)=>t.order-s.order)}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||{});const D="Content-Type";var y=(r=>(r.APPLICATION_JSON="application/json",r.TEXT_EVENT_STREAM="text/event-stream",r))(y||{});class A{constructor(){this.name="RequestBodyInterceptor",this.order=Number.MIN_SAFE_INTEGER+200}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;const s={...t};s.body=JSON.stringify(t.body),s.headers||(s.headers={});const o=s.headers;o["Content-Type"]||(o["Content-Type"]=y.APPLICATION_JSON),e.request=s}}class O{constructor(){this.name="FetchInterceptor",this.order=Number.MAX_SAFE_INTEGER-100}async intercept(e){e.response=await w(e.request)}}class q{constructor(){this.name="UrlResolveInterceptor",this.order=Number.MIN_SAFE_INTEGER+100}intercept(e){const t=e.request;t.url=e.fetcher.urlBuilder.resolveRequestUrl(t)}}class p{constructor(e=[]){this.sortedInterceptors=[],this.sortedInterceptors=f(e)}get name(){return this.constructor.name}get order(){return Number.MIN_SAFE_INTEGER}use(e){return this.sortedInterceptors.some(t=>t.name===e.name)?!1:(this.sortedInterceptors=f([...this.sortedInterceptors,e]),!0)}eject(e){const t=this.sortedInterceptors;return this.sortedInterceptors=f(t,s=>s.name!==e),t.length!==this.sortedInterceptors.length}clear(){this.sortedInterceptors=[]}async intercept(e){for(const t of this.sortedInterceptors)await t.intercept(e)}}class N{constructor(){this.request=new p([new q,new A,new O]),this.response=new p,this.error=new p}}class S{constructor(e,t,s,o){this.attributes={},this.fetcher=e,this.request=t,this.response=s,this.error=o}hasError(){return!!this.error}hasResponse(){return!!this.response}}function E(r,e){if(!(r===void 0&&e===void 0))return e===void 0?r:r===void 0?e:{...r,...e}}const g={"Content-Type":y.APPLICATION_JSON},b={baseURL:"",headers:g};class U{constructor(e=b){this.headers=g,this.urlBuilder=new R(e.baseURL),this.headers=e.headers??g,this.timeout=e.timeout,this.interceptors=e.interceptors??new N}async fetch(e,t={}){const s=t;s.url=e;const o=await this.request(s);if(!o.response)throw new l(o,`Request to ${s.url} failed with no response`);return o.response}async request(e){const t=E(e.headers,this.headers),s={...e,headers:t,timeout:P(e.timeout,this.timeout)},o=new S(this,s);return this.exchange(o)}async exchange(e){try{return await this.interceptors.request.intercept(e),await this.interceptors.response.intercept(e),e}catch(t){if(e.error=t,await this.interceptors.error.intercept(e),!e.hasError())return e;throw new d(e)}}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)}}const T="default";class L{constructor(){this.registrar=new Map}register(e,t){this.registrar.set(e,t)}unregister(e){return this.registrar.delete(e)}get(e){return this.registrar.get(e)}requiredGet(e){const t=this.get(e);if(!t)throw new Error(`Fetcher ${e} not found`);return t}get default(){return this.requiredGet(T)}set default(e){this.register(T,e)}get fetchers(){return new Map(this.registrar)}}const _=new L;function j(r,e){if(Object.keys(r).length===0)return e;if(Object.keys(e).length===0)return r;const t={path:E(r.urlParams?.path,e.urlParams?.path),query:E(r.urlParams?.query,e.urlParams?.query)},s={...r.headers,...e.headers},o=e.method??r.method,a=e.body??r.body,c=e.timeout??r.timeout,h=e.signal??r.signal;return{...r,...e,method:o,urlParams:t,headers:s,body:a,timeout:c,signal:h}}class v extends U{constructor(e,t=b){super(t),this.name=e,_.register(e,this)}}const M=new v(T);n.ContentTypeHeader=D,n.ContentTypeValues=y,n.DEFAULT_FETCHER_NAME=T,n.DEFAULT_OPTIONS=b,n.ExchangeError=d,n.FetchError=l,n.FetchExchange=S,n.FetchInterceptor=O,n.FetchTimeoutError=m,n.Fetcher=U,n.FetcherError=i,n.FetcherInterceptors=N,n.FetcherRegistrar=L,n.HttpMethod=u,n.InterceptorManager=p,n.NamedFetcher=v,n.RequestBodyInterceptor=A,n.UrlBuilder=R,n.UrlResolveInterceptor=q,n.combineURLs=I,n.fetcher=M,n.fetcherRegistrar=_,n.isAbsoluteURL=F,n.mergeRecords=E,n.mergeRequest=j,n.resolveTimeout=P,n.timeoutFetch=w,n.toSorted=f,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/timeout.d.ts
CHANGED
|
@@ -25,34 +25,6 @@ export interface TimeoutCapable {
|
|
|
25
25
|
* Otherwise, optionsTimeout is returned. If both are undefined, undefined is returned.
|
|
26
26
|
*/
|
|
27
27
|
export declare function resolveTimeout(requestTimeout?: number, optionsTimeout?: number): number | undefined;
|
|
28
|
-
/**
|
|
29
|
-
* Exception class thrown when an HTTP request times out.
|
|
30
|
-
*
|
|
31
|
-
* This error is thrown by the timeoutFetch function when a request exceeds its timeout limit.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```typescript
|
|
35
|
-
* try {
|
|
36
|
-
* const response = await timeoutFetch('https://api.example.com/users', {}, 1000);
|
|
37
|
-
* } catch (error) {
|
|
38
|
-
* if (error instanceof FetchTimeoutError) {
|
|
39
|
-
* console.log(`Request timed out after ${error.timeout}ms`);
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export declare class FetchTimeoutError extends Error {
|
|
45
|
-
/**
|
|
46
|
-
* The request options that timed out.
|
|
47
|
-
*/
|
|
48
|
-
request: FetchRequest;
|
|
49
|
-
/**
|
|
50
|
-
* Creates a new FetchTimeoutError instance.
|
|
51
|
-
*
|
|
52
|
-
* @param request - The request options that timed out
|
|
53
|
-
*/
|
|
54
|
-
constructor(request: FetchRequest);
|
|
55
|
-
}
|
|
56
28
|
/**
|
|
57
29
|
* HTTP request method with timeout control.
|
|
58
30
|
*
|
package/dist/timeout.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,GAAG,SAAS,CAKpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyC3E"}
|