react-fetch-utils 1.0.0 → 1.1.0
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 +170 -12
- package/dist/index.d.mts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +223 -22
- package/dist/index.mjs +225 -22
- package/package.json +1 -1
package/Readme.md
CHANGED
|
@@ -18,11 +18,15 @@ npm install react-fetch-utils
|
|
|
18
18
|
```ts
|
|
19
19
|
import {
|
|
20
20
|
FetchPromise,
|
|
21
|
+
createFetchClient,
|
|
21
22
|
useQueries,
|
|
22
23
|
useRequest,
|
|
23
24
|
statusEnum,
|
|
24
25
|
type CancellablePromise,
|
|
26
|
+
type FetchClientDefaults,
|
|
27
|
+
type FetchPromiseError,
|
|
25
28
|
type FetchPromiseParams,
|
|
29
|
+
type FetchRequestConfig,
|
|
26
30
|
type Status,
|
|
27
31
|
} from "react-fetch-utils";
|
|
28
32
|
```
|
|
@@ -30,11 +34,15 @@ import {
|
|
|
30
34
|
## Exports
|
|
31
35
|
|
|
32
36
|
- `FetchPromise`
|
|
37
|
+
- `createFetchClient`
|
|
33
38
|
- `useQueries`
|
|
34
39
|
- `useRequest`
|
|
35
40
|
- `statusEnum`
|
|
36
41
|
- `CancellablePromise` (type)
|
|
42
|
+
- `FetchClientDefaults` (type)
|
|
43
|
+
- `FetchPromiseError` (type)
|
|
37
44
|
- `FetchPromiseParams` (type)
|
|
45
|
+
- `FetchRequestConfig` (type)
|
|
38
46
|
- `Status` (type)
|
|
39
47
|
|
|
40
48
|
## Quick Start
|
|
@@ -86,22 +94,49 @@ function FetchPromise<T = unknown>(
|
|
|
86
94
|
type FetchPromiseParams = {
|
|
87
95
|
url: string;
|
|
88
96
|
method: string;
|
|
89
|
-
body?:
|
|
97
|
+
body?: unknown;
|
|
90
98
|
respType?: "raw" | "json" | null;
|
|
99
|
+
headers?: HeadersInit | Record<string, string>;
|
|
100
|
+
timeoutMs?: number;
|
|
101
|
+
baseUrl?: string;
|
|
102
|
+
includeContentType?: boolean;
|
|
103
|
+
parseAs?: "json" | "raw" | "text" | "response";
|
|
104
|
+
onRequest?: (
|
|
105
|
+
request: FetchRequestConfig,
|
|
106
|
+
) => FetchRequestConfig | void | Promise<FetchRequestConfig | void>;
|
|
107
|
+
validateStatus?: (status: number, response: Response) => boolean;
|
|
108
|
+
getAuthToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
109
|
+
allowBodyForGetHead?: boolean;
|
|
91
110
|
};
|
|
92
111
|
```
|
|
93
112
|
|
|
94
113
|
Behavior:
|
|
95
114
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
- `
|
|
99
|
-
- `
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
115
|
+
- Backward compatible with existing `respType: "json" | "raw"`.
|
|
116
|
+
- New parsing modes via `parseAs`:
|
|
117
|
+
- `json` (default)
|
|
118
|
+
- `raw` (`Blob`)
|
|
119
|
+
- `text` (`string`)
|
|
120
|
+
- `response` (`Response`)
|
|
121
|
+
- Supports request timeout with `timeoutMs` using `AbortController`.
|
|
122
|
+
- Supports base URL joining with `baseUrl`.
|
|
123
|
+
- Supports request customization with `headers`, `onRequest`, `validateStatus`, and `getAuthToken`.
|
|
124
|
+
- `Accept` is set automatically only when caller did not provide it.
|
|
125
|
+
- `Content-Type: application/json` is added only when:
|
|
126
|
+
- there is a body,
|
|
127
|
+
- method is `POST`/`PUT`/`PATCH`,
|
|
128
|
+
- `includeContentType !== false`,
|
|
129
|
+
- caller did not already provide `Content-Type`.
|
|
130
|
+
- Request body behavior:
|
|
131
|
+
- `GET`/`HEAD` bodies are not sent by default.
|
|
132
|
+
- use `allowBodyForGetHead: true` to allow body on `GET`/`HEAD`.
|
|
133
|
+
- non-JSON bodies (`FormData`, `Blob`, `string`, `URLSearchParams`, etc.) are passed through unchanged.
|
|
134
|
+
- plain objects/values are JSON-stringified when body is allowed.
|
|
135
|
+
- Error model:
|
|
136
|
+
- `401` rejects with `{ reason: "Unauthorized", details: Response }`
|
|
137
|
+
- timeout abort rejects with `{ reason: "Timeout", details: ... }`
|
|
138
|
+
- other failures reject with `{ reason: "Unknown", details: ... }`
|
|
139
|
+
- Returned promise remains cancellable with `.cancel()` and is safe to call repeatedly.
|
|
105
140
|
|
|
106
141
|
Example (JSON):
|
|
107
142
|
|
|
@@ -112,9 +147,41 @@ type User = { id: number; name: string };
|
|
|
112
147
|
|
|
113
148
|
export function getUser() {
|
|
114
149
|
return FetchPromise<User>({
|
|
115
|
-
url: "/
|
|
150
|
+
url: "/user",
|
|
116
151
|
method: "POST",
|
|
152
|
+
baseUrl: "https://api.example.com/v1",
|
|
117
153
|
body: { includeDetails: true },
|
|
154
|
+
timeoutMs: 8000,
|
|
155
|
+
getAuthToken: () => localStorage.getItem("token"),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Example (`text` parse mode + custom status validation):
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { FetchPromise } from "react-fetch-utils";
|
|
164
|
+
|
|
165
|
+
export function getHealth() {
|
|
166
|
+
return FetchPromise<string>({
|
|
167
|
+
url: "/health",
|
|
168
|
+
method: "GET",
|
|
169
|
+
parseAs: "text",
|
|
170
|
+
validateStatus: status => status >= 200 && status < 500,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Example (full `Response` mode):
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { FetchPromise } from "react-fetch-utils";
|
|
179
|
+
|
|
180
|
+
export function getRawResponse() {
|
|
181
|
+
return FetchPromise<Response>({
|
|
182
|
+
url: "/diagnostics",
|
|
183
|
+
method: "GET",
|
|
184
|
+
parseAs: "response",
|
|
118
185
|
});
|
|
119
186
|
}
|
|
120
187
|
```
|
|
@@ -134,6 +201,64 @@ const download = FetchPromise<Blob>({
|
|
|
134
201
|
download.cancel();
|
|
135
202
|
```
|
|
136
203
|
|
|
204
|
+
### `createFetchClient`
|
|
205
|
+
|
|
206
|
+
Creates a reusable request function with merged defaults so app code does not need a custom API wrapper utility.
|
|
207
|
+
|
|
208
|
+
Signature:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
function createFetchClient(
|
|
212
|
+
defaults?: FetchClientDefaults,
|
|
213
|
+
): <T = unknown>(params: FetchPromiseParams) => CancellablePromise<T>;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Example (replace a custom `APIRequest` utility):
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { createFetchClient } from "react-fetch-utils";
|
|
220
|
+
|
|
221
|
+
export const apiRequest = createFetchClient({
|
|
222
|
+
baseUrl: "https://api.example.com/v1",
|
|
223
|
+
timeoutMs: 10000,
|
|
224
|
+
headers: {
|
|
225
|
+
"X-App-Client": "web",
|
|
226
|
+
},
|
|
227
|
+
getAuthToken: async () => localStorage.getItem("access_token"),
|
|
228
|
+
validateStatus: status => status >= 200 && status < 300,
|
|
229
|
+
onRequest: request => {
|
|
230
|
+
request.headers.set("X-Trace-Id", crypto.randomUUID());
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
export const getProfile = () =>
|
|
235
|
+
apiRequest<{ id: string; name: string }>({
|
|
236
|
+
url: "/profile",
|
|
237
|
+
method: "GET",
|
|
238
|
+
parseAs: "json",
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
export const downloadReport = () =>
|
|
242
|
+
apiRequest<Blob>({
|
|
243
|
+
url: "/reports/monthly",
|
|
244
|
+
method: "GET",
|
|
245
|
+
parseAs: "raw",
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Example (`FormData` upload without forced JSON content-type):
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const formData = new FormData();
|
|
253
|
+
formData.append("file", file);
|
|
254
|
+
|
|
255
|
+
apiRequest({
|
|
256
|
+
url: "/upload",
|
|
257
|
+
method: "POST",
|
|
258
|
+
body: formData,
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
137
262
|
### `useQueries`
|
|
138
263
|
|
|
139
264
|
Tracks active cancellable promises and provides list management helpers.
|
|
@@ -295,12 +420,44 @@ const request: FetchPromiseParams = {
|
|
|
295
420
|
url: "/api/items",
|
|
296
421
|
method: "POST",
|
|
297
422
|
body: { page: 1 },
|
|
298
|
-
|
|
423
|
+
headers: { Authorization: "Bearer token" },
|
|
424
|
+
timeoutMs: 5000,
|
|
425
|
+
parseAs: "json",
|
|
299
426
|
};
|
|
300
427
|
|
|
301
428
|
FetchPromise(request);
|
|
302
429
|
```
|
|
303
430
|
|
|
431
|
+
### `FetchPromiseError` (type)
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
type FetchPromiseError = {
|
|
435
|
+
reason: "Unauthorized" | "Timeout" | "Unknown";
|
|
436
|
+
details: unknown;
|
|
437
|
+
status?: number;
|
|
438
|
+
response?: Response;
|
|
439
|
+
originalError?: unknown;
|
|
440
|
+
};
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### `FetchRequestConfig` (type)
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
type FetchRequestConfig = {
|
|
447
|
+
url: string;
|
|
448
|
+
init: RequestInit;
|
|
449
|
+
headers: Headers;
|
|
450
|
+
};
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### `FetchClientDefaults` (type)
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
type FetchClientDefaults = Omit<FetchPromiseParams, "url" | "method"> & {
|
|
457
|
+
method?: string;
|
|
458
|
+
};
|
|
459
|
+
```
|
|
460
|
+
|
|
304
461
|
### `Status` (type)
|
|
305
462
|
|
|
306
463
|
```ts
|
|
@@ -320,6 +477,7 @@ console.log(statusEnum[status]); // "fetching"
|
|
|
320
477
|
|
|
321
478
|
- `useRequest` is built on top of `useQueries`.
|
|
322
479
|
- For errors, attach `.catch(...)` where you create and consume `CancellablePromise` requests.
|
|
480
|
+
- `respType` is still supported for backward compatibility; prefer `parseAs` in new code.
|
|
323
481
|
|
|
324
482
|
## License
|
|
325
483
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
interface FetchPromiseParams {
|
|
2
2
|
url: string;
|
|
3
3
|
method: string;
|
|
4
|
-
body?:
|
|
4
|
+
body?: unknown;
|
|
5
5
|
respType?: "raw" | "json" | null;
|
|
6
|
+
headers?: HeadersInit | Record<string, string>;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
includeContentType?: boolean;
|
|
10
|
+
parseAs?: "json" | "raw" | "text" | "response";
|
|
11
|
+
onRequest?: (request: FetchRequestConfig) => FetchRequestConfig | void | Promise<FetchRequestConfig | void>;
|
|
12
|
+
validateStatus?: (status: number, response: Response) => boolean;
|
|
13
|
+
getAuthToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
14
|
+
allowBodyForGetHead?: boolean;
|
|
6
15
|
}
|
|
16
|
+
interface FetchRequestConfig {
|
|
17
|
+
url: string;
|
|
18
|
+
init: RequestInit;
|
|
19
|
+
headers: Headers;
|
|
20
|
+
}
|
|
21
|
+
interface FetchPromiseError {
|
|
22
|
+
reason: "Unauthorized" | "Timeout" | "Unknown";
|
|
23
|
+
details: unknown;
|
|
24
|
+
status?: number;
|
|
25
|
+
response?: Response;
|
|
26
|
+
originalError?: unknown;
|
|
27
|
+
}
|
|
28
|
+
type FetchClientDefaults = Omit<FetchPromiseParams, "url" | "method"> & {
|
|
29
|
+
method?: string;
|
|
30
|
+
};
|
|
7
31
|
interface CancellablePromise<T = unknown> extends Promise<T> {
|
|
8
32
|
cancel: () => void;
|
|
9
33
|
}
|
|
@@ -12,6 +36,7 @@ interface CancellablePromise<T = unknown> extends Promise<T> {
|
|
|
12
36
|
* @returns A promise with a `.cancel()` method that calls `AbortController.abort()`
|
|
13
37
|
*/
|
|
14
38
|
declare const FetchPromise: <T = unknown>(params: FetchPromiseParams) => CancellablePromise<T>;
|
|
39
|
+
declare const createFetchClient: (defaults?: FetchClientDefaults) => <T = unknown>(params: FetchPromiseParams) => CancellablePromise<T>;
|
|
15
40
|
|
|
16
41
|
declare function useQueries(): {
|
|
17
42
|
list: CancellablePromise<unknown>[];
|
|
@@ -42,4 +67,4 @@ declare const useRequest: <T = unknown>(fetchPromise: (() => CancellablePromise<
|
|
|
42
67
|
response: T | null;
|
|
43
68
|
};
|
|
44
69
|
|
|
45
|
-
export { type CancellablePromise, FetchPromise, type FetchPromiseParams, type Status, statusEnum, useQueries, useRequest };
|
|
70
|
+
export { type CancellablePromise, type FetchClientDefaults, FetchPromise, type FetchPromiseError, type FetchPromiseParams, type FetchRequestConfig, type Status, createFetchClient, statusEnum, useQueries, useRequest };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
interface FetchPromiseParams {
|
|
2
2
|
url: string;
|
|
3
3
|
method: string;
|
|
4
|
-
body?:
|
|
4
|
+
body?: unknown;
|
|
5
5
|
respType?: "raw" | "json" | null;
|
|
6
|
+
headers?: HeadersInit | Record<string, string>;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
includeContentType?: boolean;
|
|
10
|
+
parseAs?: "json" | "raw" | "text" | "response";
|
|
11
|
+
onRequest?: (request: FetchRequestConfig) => FetchRequestConfig | void | Promise<FetchRequestConfig | void>;
|
|
12
|
+
validateStatus?: (status: number, response: Response) => boolean;
|
|
13
|
+
getAuthToken?: () => string | null | undefined | Promise<string | null | undefined>;
|
|
14
|
+
allowBodyForGetHead?: boolean;
|
|
6
15
|
}
|
|
16
|
+
interface FetchRequestConfig {
|
|
17
|
+
url: string;
|
|
18
|
+
init: RequestInit;
|
|
19
|
+
headers: Headers;
|
|
20
|
+
}
|
|
21
|
+
interface FetchPromiseError {
|
|
22
|
+
reason: "Unauthorized" | "Timeout" | "Unknown";
|
|
23
|
+
details: unknown;
|
|
24
|
+
status?: number;
|
|
25
|
+
response?: Response;
|
|
26
|
+
originalError?: unknown;
|
|
27
|
+
}
|
|
28
|
+
type FetchClientDefaults = Omit<FetchPromiseParams, "url" | "method"> & {
|
|
29
|
+
method?: string;
|
|
30
|
+
};
|
|
7
31
|
interface CancellablePromise<T = unknown> extends Promise<T> {
|
|
8
32
|
cancel: () => void;
|
|
9
33
|
}
|
|
@@ -12,6 +36,7 @@ interface CancellablePromise<T = unknown> extends Promise<T> {
|
|
|
12
36
|
* @returns A promise with a `.cancel()` method that calls `AbortController.abort()`
|
|
13
37
|
*/
|
|
14
38
|
declare const FetchPromise: <T = unknown>(params: FetchPromiseParams) => CancellablePromise<T>;
|
|
39
|
+
declare const createFetchClient: (defaults?: FetchClientDefaults) => <T = unknown>(params: FetchPromiseParams) => CancellablePromise<T>;
|
|
15
40
|
|
|
16
41
|
declare function useQueries(): {
|
|
17
42
|
list: CancellablePromise<unknown>[];
|
|
@@ -42,4 +67,4 @@ declare const useRequest: <T = unknown>(fetchPromise: (() => CancellablePromise<
|
|
|
42
67
|
response: T | null;
|
|
43
68
|
};
|
|
44
69
|
|
|
45
|
-
export { type CancellablePromise, FetchPromise, type FetchPromiseParams, type Status, statusEnum, useQueries, useRequest };
|
|
70
|
+
export { type CancellablePromise, type FetchClientDefaults, FetchPromise, type FetchPromiseError, type FetchPromiseParams, type FetchRequestConfig, type Status, createFetchClient, statusEnum, useQueries, useRequest };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
6
23
|
var __export = (target, all) => {
|
|
7
24
|
for (var name in all)
|
|
8
25
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -21,6 +38,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
38
|
var index_exports = {};
|
|
22
39
|
__export(index_exports, {
|
|
23
40
|
FetchPromise: () => FetchPromise_default,
|
|
41
|
+
createFetchClient: () => createFetchClient,
|
|
24
42
|
statusEnum: () => statusEnum,
|
|
25
43
|
useQueries: () => useQueries,
|
|
26
44
|
useRequest: () => useRequest
|
|
@@ -28,39 +46,221 @@ __export(index_exports, {
|
|
|
28
46
|
module.exports = __toCommonJS(index_exports);
|
|
29
47
|
|
|
30
48
|
// src/FetchPromise.ts
|
|
49
|
+
var METHODS_WITH_DEFAULT_BODY = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
50
|
+
var METHODS_WITHOUT_BODY = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
51
|
+
var isBodyInitLike = (value) => {
|
|
52
|
+
if (typeof value === "string") return true;
|
|
53
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) return true;
|
|
54
|
+
if (typeof FormData !== "undefined" && value instanceof FormData) return true;
|
|
55
|
+
if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) return true;
|
|
56
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) return true;
|
|
57
|
+
if (typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer) return true;
|
|
58
|
+
if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value)) return true;
|
|
59
|
+
return false;
|
|
60
|
+
};
|
|
61
|
+
var mapParseMode = (parseAs, respType) => {
|
|
62
|
+
if (parseAs) return parseAs;
|
|
63
|
+
if (respType === "raw") return "raw";
|
|
64
|
+
return "json";
|
|
65
|
+
};
|
|
66
|
+
var mergeHeaders = (defaults, overrides) => {
|
|
67
|
+
const headers = new Headers(defaults != null ? defaults : {});
|
|
68
|
+
if (overrides) {
|
|
69
|
+
new Headers(overrides).forEach((value, key) => {
|
|
70
|
+
headers.set(key, value);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return headers;
|
|
74
|
+
};
|
|
75
|
+
var resolveUrl = (url, baseUrl) => {
|
|
76
|
+
if (!baseUrl) return url;
|
|
77
|
+
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(url) || url.startsWith("//")) {
|
|
78
|
+
return url;
|
|
79
|
+
}
|
|
80
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
81
|
+
const normalizedPath = url.startsWith("/") ? url : `/${url}`;
|
|
82
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
83
|
+
};
|
|
84
|
+
var parseJsonSafely = async (response) => {
|
|
85
|
+
if (response.status === 204 || response.status === 205) {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
const text = await response.text();
|
|
89
|
+
if (!text.trim()) {
|
|
90
|
+
return void 0;
|
|
91
|
+
}
|
|
92
|
+
return JSON.parse(text);
|
|
93
|
+
};
|
|
94
|
+
var normalizeErrorDetails = (error) => {
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
return {
|
|
97
|
+
name: error.name,
|
|
98
|
+
message: error.message,
|
|
99
|
+
stack: error.stack
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return error;
|
|
103
|
+
};
|
|
31
104
|
var FetchPromise = (params) => {
|
|
32
105
|
const controller = new AbortController();
|
|
33
106
|
const signal = controller.signal;
|
|
107
|
+
let timeoutId;
|
|
108
|
+
let timedOut = false;
|
|
109
|
+
let cancelled = false;
|
|
34
110
|
const promise = new Promise(async function(resolve, reject) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
111
|
+
try {
|
|
112
|
+
const method = params.method.toUpperCase();
|
|
113
|
+
const parseAs = mapParseMode(params.parseAs, params.respType);
|
|
114
|
+
const headers = mergeHeaders(void 0, params.headers);
|
|
115
|
+
if (!headers.has("Accept")) {
|
|
116
|
+
if (parseAs === "raw") {
|
|
117
|
+
headers.set("Accept", "blob");
|
|
118
|
+
} else if (parseAs === "json") {
|
|
119
|
+
headers.set("Accept", "application/json");
|
|
120
|
+
} else {
|
|
121
|
+
headers.set("Accept", "*/*");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!headers.has("Authorization") && params.getAuthToken) {
|
|
125
|
+
const token = await params.getAuthToken();
|
|
126
|
+
if (token) {
|
|
127
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const hasBodyValue = params.body !== void 0 && params.body !== null;
|
|
131
|
+
const allowsBody = !METHODS_WITHOUT_BODY.has(method) || params.allowBodyForGetHead === true;
|
|
132
|
+
const shouldSendBody = hasBodyValue && allowsBody;
|
|
133
|
+
let body;
|
|
134
|
+
let isJsonBody = false;
|
|
135
|
+
if (shouldSendBody) {
|
|
136
|
+
if (isBodyInitLike(params.body)) {
|
|
137
|
+
body = params.body;
|
|
138
|
+
} else {
|
|
139
|
+
body = JSON.stringify(params.body);
|
|
140
|
+
isJsonBody = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (shouldSendBody && isJsonBody && params.includeContentType !== false && !headers.has("Content-Type") && METHODS_WITH_DEFAULT_BODY.has(method)) {
|
|
144
|
+
headers.set("Content-Type", "application/json");
|
|
145
|
+
}
|
|
146
|
+
const requestConfig = {
|
|
147
|
+
url: resolveUrl(params.url, params.baseUrl),
|
|
148
|
+
init: {
|
|
149
|
+
method,
|
|
150
|
+
signal,
|
|
151
|
+
headers,
|
|
152
|
+
body
|
|
153
|
+
},
|
|
154
|
+
headers
|
|
155
|
+
};
|
|
156
|
+
if (params.onRequest) {
|
|
157
|
+
const maybeUpdatedConfig = await params.onRequest(requestConfig);
|
|
158
|
+
if (maybeUpdatedConfig) {
|
|
159
|
+
requestConfig.url = maybeUpdatedConfig.url;
|
|
160
|
+
requestConfig.init = maybeUpdatedConfig.init;
|
|
161
|
+
requestConfig.headers = maybeUpdatedConfig.headers;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (typeof params.timeoutMs === "number" && params.timeoutMs > 0) {
|
|
165
|
+
timeoutId = setTimeout(() => {
|
|
166
|
+
timedOut = true;
|
|
167
|
+
controller.abort();
|
|
168
|
+
}, params.timeoutMs);
|
|
169
|
+
}
|
|
170
|
+
const response = await fetch(requestConfig.url, __spreadProps(__spreadValues({}, requestConfig.init), {
|
|
171
|
+
signal,
|
|
172
|
+
headers: requestConfig.headers
|
|
173
|
+
}));
|
|
45
174
|
if (response.status === 401) {
|
|
46
|
-
reject({ reason: "Unauthorized", details: response });
|
|
175
|
+
reject({ reason: "Unauthorized", details: response, status: 401, response });
|
|
176
|
+
return;
|
|
47
177
|
}
|
|
48
|
-
|
|
49
|
-
|
|
178
|
+
const isValid = params.validateStatus ? params.validateStatus(response.status, response) : response.ok;
|
|
179
|
+
if (!isValid) {
|
|
180
|
+
reject({
|
|
181
|
+
reason: "Unknown",
|
|
182
|
+
details: {
|
|
183
|
+
status: response.status,
|
|
184
|
+
statusText: response.statusText,
|
|
185
|
+
response
|
|
186
|
+
},
|
|
187
|
+
status: response.status,
|
|
188
|
+
response
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
50
191
|
}
|
|
51
|
-
if (
|
|
52
|
-
|
|
192
|
+
if (parseAs === "response") {
|
|
193
|
+
resolve(response);
|
|
194
|
+
return;
|
|
53
195
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
196
|
+
if (parseAs === "raw") {
|
|
197
|
+
resolve(await response.blob());
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (parseAs === "text") {
|
|
201
|
+
resolve(await response.text());
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
resolve(await parseJsonSafely(response));
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (timedOut && (error == null ? void 0 : error.name) === "AbortError") {
|
|
207
|
+
reject({
|
|
208
|
+
reason: "Timeout",
|
|
209
|
+
details: {
|
|
210
|
+
timeoutMs: params.timeoutMs,
|
|
211
|
+
abortError: normalizeErrorDetails(error)
|
|
212
|
+
},
|
|
213
|
+
originalError: error
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
reject({
|
|
218
|
+
reason: "Unknown",
|
|
219
|
+
details: normalizeErrorDetails(error),
|
|
220
|
+
originalError: error
|
|
221
|
+
});
|
|
222
|
+
} finally {
|
|
223
|
+
if (timeoutId) {
|
|
224
|
+
clearTimeout(timeoutId);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
60
227
|
});
|
|
61
|
-
promise.cancel = () =>
|
|
228
|
+
promise.cancel = () => {
|
|
229
|
+
if (cancelled) return;
|
|
230
|
+
cancelled = true;
|
|
231
|
+
controller.abort();
|
|
232
|
+
};
|
|
62
233
|
return promise;
|
|
63
234
|
};
|
|
235
|
+
var createFetchClient = (defaults = {}) => {
|
|
236
|
+
return (params) => {
|
|
237
|
+
var _a, _b, _c, _d;
|
|
238
|
+
const runDefaultOnRequest = defaults.onRequest;
|
|
239
|
+
const runParamOnRequest = params.onRequest;
|
|
240
|
+
return FetchPromise(__spreadProps(__spreadValues(__spreadValues({}, defaults), params), {
|
|
241
|
+
method: (_b = (_a = params.method) != null ? _a : defaults.method) != null ? _b : "GET",
|
|
242
|
+
headers: mergeHeaders(defaults.headers, params.headers),
|
|
243
|
+
onRequest: async (request) => {
|
|
244
|
+
let nextRequest = request;
|
|
245
|
+
if (runDefaultOnRequest) {
|
|
246
|
+
const maybeDefaultUpdated = await runDefaultOnRequest(nextRequest);
|
|
247
|
+
if (maybeDefaultUpdated) {
|
|
248
|
+
nextRequest = maybeDefaultUpdated;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (runParamOnRequest) {
|
|
252
|
+
const maybeParamUpdated = await runParamOnRequest(nextRequest);
|
|
253
|
+
if (maybeParamUpdated) {
|
|
254
|
+
nextRequest = maybeParamUpdated;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return nextRequest;
|
|
258
|
+
},
|
|
259
|
+
validateStatus: (_c = params.validateStatus) != null ? _c : defaults.validateStatus,
|
|
260
|
+
getAuthToken: (_d = params.getAuthToken) != null ? _d : defaults.getAuthToken
|
|
261
|
+
}));
|
|
262
|
+
};
|
|
263
|
+
};
|
|
64
264
|
var FetchPromise_default = FetchPromise;
|
|
65
265
|
|
|
66
266
|
// src/useQueries.ts
|
|
@@ -121,6 +321,7 @@ var useRequest = (fetchPromise, disableCache = false) => {
|
|
|
121
321
|
// Annotate the CommonJS export names for ESM import in node:
|
|
122
322
|
0 && (module.exports = {
|
|
123
323
|
FetchPromise,
|
|
324
|
+
createFetchClient,
|
|
124
325
|
statusEnum,
|
|
125
326
|
useQueries,
|
|
126
327
|
useRequest
|
package/dist/index.mjs
CHANGED
|
@@ -1,37 +1,239 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
|
|
1
21
|
// src/FetchPromise.ts
|
|
22
|
+
var METHODS_WITH_DEFAULT_BODY = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
23
|
+
var METHODS_WITHOUT_BODY = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
24
|
+
var isBodyInitLike = (value) => {
|
|
25
|
+
if (typeof value === "string") return true;
|
|
26
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) return true;
|
|
27
|
+
if (typeof FormData !== "undefined" && value instanceof FormData) return true;
|
|
28
|
+
if (typeof URLSearchParams !== "undefined" && value instanceof URLSearchParams) return true;
|
|
29
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) return true;
|
|
30
|
+
if (typeof ArrayBuffer !== "undefined" && value instanceof ArrayBuffer) return true;
|
|
31
|
+
if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(value)) return true;
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
var mapParseMode = (parseAs, respType) => {
|
|
35
|
+
if (parseAs) return parseAs;
|
|
36
|
+
if (respType === "raw") return "raw";
|
|
37
|
+
return "json";
|
|
38
|
+
};
|
|
39
|
+
var mergeHeaders = (defaults, overrides) => {
|
|
40
|
+
const headers = new Headers(defaults != null ? defaults : {});
|
|
41
|
+
if (overrides) {
|
|
42
|
+
new Headers(overrides).forEach((value, key) => {
|
|
43
|
+
headers.set(key, value);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return headers;
|
|
47
|
+
};
|
|
48
|
+
var resolveUrl = (url, baseUrl) => {
|
|
49
|
+
if (!baseUrl) return url;
|
|
50
|
+
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(url) || url.startsWith("//")) {
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
54
|
+
const normalizedPath = url.startsWith("/") ? url : `/${url}`;
|
|
55
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
56
|
+
};
|
|
57
|
+
var parseJsonSafely = async (response) => {
|
|
58
|
+
if (response.status === 204 || response.status === 205) {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
const text = await response.text();
|
|
62
|
+
if (!text.trim()) {
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
return JSON.parse(text);
|
|
66
|
+
};
|
|
67
|
+
var normalizeErrorDetails = (error) => {
|
|
68
|
+
if (error instanceof Error) {
|
|
69
|
+
return {
|
|
70
|
+
name: error.name,
|
|
71
|
+
message: error.message,
|
|
72
|
+
stack: error.stack
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return error;
|
|
76
|
+
};
|
|
2
77
|
var FetchPromise = (params) => {
|
|
3
78
|
const controller = new AbortController();
|
|
4
79
|
const signal = controller.signal;
|
|
80
|
+
let timeoutId;
|
|
81
|
+
let timedOut = false;
|
|
82
|
+
let cancelled = false;
|
|
5
83
|
const promise = new Promise(async function(resolve, reject) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
84
|
+
try {
|
|
85
|
+
const method = params.method.toUpperCase();
|
|
86
|
+
const parseAs = mapParseMode(params.parseAs, params.respType);
|
|
87
|
+
const headers = mergeHeaders(void 0, params.headers);
|
|
88
|
+
if (!headers.has("Accept")) {
|
|
89
|
+
if (parseAs === "raw") {
|
|
90
|
+
headers.set("Accept", "blob");
|
|
91
|
+
} else if (parseAs === "json") {
|
|
92
|
+
headers.set("Accept", "application/json");
|
|
93
|
+
} else {
|
|
94
|
+
headers.set("Accept", "*/*");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!headers.has("Authorization") && params.getAuthToken) {
|
|
98
|
+
const token = await params.getAuthToken();
|
|
99
|
+
if (token) {
|
|
100
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const hasBodyValue = params.body !== void 0 && params.body !== null;
|
|
104
|
+
const allowsBody = !METHODS_WITHOUT_BODY.has(method) || params.allowBodyForGetHead === true;
|
|
105
|
+
const shouldSendBody = hasBodyValue && allowsBody;
|
|
106
|
+
let body;
|
|
107
|
+
let isJsonBody = false;
|
|
108
|
+
if (shouldSendBody) {
|
|
109
|
+
if (isBodyInitLike(params.body)) {
|
|
110
|
+
body = params.body;
|
|
111
|
+
} else {
|
|
112
|
+
body = JSON.stringify(params.body);
|
|
113
|
+
isJsonBody = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (shouldSendBody && isJsonBody && params.includeContentType !== false && !headers.has("Content-Type") && METHODS_WITH_DEFAULT_BODY.has(method)) {
|
|
117
|
+
headers.set("Content-Type", "application/json");
|
|
118
|
+
}
|
|
119
|
+
const requestConfig = {
|
|
120
|
+
url: resolveUrl(params.url, params.baseUrl),
|
|
121
|
+
init: {
|
|
122
|
+
method,
|
|
123
|
+
signal,
|
|
124
|
+
headers,
|
|
125
|
+
body
|
|
126
|
+
},
|
|
127
|
+
headers
|
|
128
|
+
};
|
|
129
|
+
if (params.onRequest) {
|
|
130
|
+
const maybeUpdatedConfig = await params.onRequest(requestConfig);
|
|
131
|
+
if (maybeUpdatedConfig) {
|
|
132
|
+
requestConfig.url = maybeUpdatedConfig.url;
|
|
133
|
+
requestConfig.init = maybeUpdatedConfig.init;
|
|
134
|
+
requestConfig.headers = maybeUpdatedConfig.headers;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (typeof params.timeoutMs === "number" && params.timeoutMs > 0) {
|
|
138
|
+
timeoutId = setTimeout(() => {
|
|
139
|
+
timedOut = true;
|
|
140
|
+
controller.abort();
|
|
141
|
+
}, params.timeoutMs);
|
|
142
|
+
}
|
|
143
|
+
const response = await fetch(requestConfig.url, __spreadProps(__spreadValues({}, requestConfig.init), {
|
|
144
|
+
signal,
|
|
145
|
+
headers: requestConfig.headers
|
|
146
|
+
}));
|
|
16
147
|
if (response.status === 401) {
|
|
17
|
-
reject({ reason: "Unauthorized", details: response });
|
|
148
|
+
reject({ reason: "Unauthorized", details: response, status: 401, response });
|
|
149
|
+
return;
|
|
18
150
|
}
|
|
19
|
-
|
|
20
|
-
|
|
151
|
+
const isValid = params.validateStatus ? params.validateStatus(response.status, response) : response.ok;
|
|
152
|
+
if (!isValid) {
|
|
153
|
+
reject({
|
|
154
|
+
reason: "Unknown",
|
|
155
|
+
details: {
|
|
156
|
+
status: response.status,
|
|
157
|
+
statusText: response.statusText,
|
|
158
|
+
response
|
|
159
|
+
},
|
|
160
|
+
status: response.status,
|
|
161
|
+
response
|
|
162
|
+
});
|
|
163
|
+
return;
|
|
21
164
|
}
|
|
22
|
-
if (
|
|
23
|
-
|
|
165
|
+
if (parseAs === "response") {
|
|
166
|
+
resolve(response);
|
|
167
|
+
return;
|
|
24
168
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
169
|
+
if (parseAs === "raw") {
|
|
170
|
+
resolve(await response.blob());
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (parseAs === "text") {
|
|
174
|
+
resolve(await response.text());
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
resolve(await parseJsonSafely(response));
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (timedOut && (error == null ? void 0 : error.name) === "AbortError") {
|
|
180
|
+
reject({
|
|
181
|
+
reason: "Timeout",
|
|
182
|
+
details: {
|
|
183
|
+
timeoutMs: params.timeoutMs,
|
|
184
|
+
abortError: normalizeErrorDetails(error)
|
|
185
|
+
},
|
|
186
|
+
originalError: error
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
reject({
|
|
191
|
+
reason: "Unknown",
|
|
192
|
+
details: normalizeErrorDetails(error),
|
|
193
|
+
originalError: error
|
|
194
|
+
});
|
|
195
|
+
} finally {
|
|
196
|
+
if (timeoutId) {
|
|
197
|
+
clearTimeout(timeoutId);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
31
200
|
});
|
|
32
|
-
promise.cancel = () =>
|
|
201
|
+
promise.cancel = () => {
|
|
202
|
+
if (cancelled) return;
|
|
203
|
+
cancelled = true;
|
|
204
|
+
controller.abort();
|
|
205
|
+
};
|
|
33
206
|
return promise;
|
|
34
207
|
};
|
|
208
|
+
var createFetchClient = (defaults = {}) => {
|
|
209
|
+
return (params) => {
|
|
210
|
+
var _a, _b, _c, _d;
|
|
211
|
+
const runDefaultOnRequest = defaults.onRequest;
|
|
212
|
+
const runParamOnRequest = params.onRequest;
|
|
213
|
+
return FetchPromise(__spreadProps(__spreadValues(__spreadValues({}, defaults), params), {
|
|
214
|
+
method: (_b = (_a = params.method) != null ? _a : defaults.method) != null ? _b : "GET",
|
|
215
|
+
headers: mergeHeaders(defaults.headers, params.headers),
|
|
216
|
+
onRequest: async (request) => {
|
|
217
|
+
let nextRequest = request;
|
|
218
|
+
if (runDefaultOnRequest) {
|
|
219
|
+
const maybeDefaultUpdated = await runDefaultOnRequest(nextRequest);
|
|
220
|
+
if (maybeDefaultUpdated) {
|
|
221
|
+
nextRequest = maybeDefaultUpdated;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (runParamOnRequest) {
|
|
225
|
+
const maybeParamUpdated = await runParamOnRequest(nextRequest);
|
|
226
|
+
if (maybeParamUpdated) {
|
|
227
|
+
nextRequest = maybeParamUpdated;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return nextRequest;
|
|
231
|
+
},
|
|
232
|
+
validateStatus: (_c = params.validateStatus) != null ? _c : defaults.validateStatus,
|
|
233
|
+
getAuthToken: (_d = params.getAuthToken) != null ? _d : defaults.getAuthToken
|
|
234
|
+
}));
|
|
235
|
+
};
|
|
236
|
+
};
|
|
35
237
|
var FetchPromise_default = FetchPromise;
|
|
36
238
|
|
|
37
239
|
// src/useQueries.ts
|
|
@@ -91,6 +293,7 @@ var useRequest = (fetchPromise, disableCache = false) => {
|
|
|
91
293
|
};
|
|
92
294
|
export {
|
|
93
295
|
FetchPromise_default as FetchPromise,
|
|
296
|
+
createFetchClient,
|
|
94
297
|
statusEnum,
|
|
95
298
|
useQueries,
|
|
96
299
|
useRequest
|